diff options
author | Iccha Sethi <iccha.sethi@rackspace.com> | 2014-09-17 14:41:19 -0500 |
---|---|---|
committer | Nikhil Manchanda <SlickNik@gmail.com> | 2014-10-01 03:31:48 -0700 |
commit | 957f72bf311d5c76c5e2f5fffdee4aebd12c56a5 (patch) | |
tree | e043a0c23efac4b909fc80aeb691922330fe7c2f | |
parent | ba3a43f2c5d3233118f0cb152a299c29e6018d36 (diff) | |
download | trove-957f72bf311d5c76c5e2f5fffdee4aebd12c56a5.tar.gz |
Add templates for replica and replica source
This patch adds templates for replica and replica source.
Previously this was hard coded in the code. This gives
deployers the ability to customize their replication
configurations.
Closes-Bug: 1370125
Change-Id: Ie1b4cff1685d2577240eb43ffecac3c977ba964c
-rw-r--r-- | trove/common/template.py | 8 | ||||
-rw-r--r-- | trove/guestagent/api.py | 10 | ||||
-rw-r--r-- | trove/guestagent/datastore/cassandra/manager.py | 3 | ||||
-rw-r--r-- | trove/guestagent/datastore/couchbase/manager.py | 3 | ||||
-rw-r--r-- | trove/guestagent/datastore/mongodb/manager.py | 3 | ||||
-rw-r--r-- | trove/guestagent/datastore/mysql/manager.py | 8 | ||||
-rw-r--r-- | trove/guestagent/datastore/mysql/service.py | 2 | ||||
-rw-r--r-- | trove/guestagent/datastore/redis/manager.py | 3 | ||||
-rw-r--r-- | trove/guestagent/strategies/replication/mysql_binlog.py | 12 | ||||
-rw-r--r-- | trove/taskmanager/manager.py | 2 | ||||
-rwxr-xr-x | trove/taskmanager/models.py | 27 | ||||
-rw-r--r-- | trove/templates/mysql/replica.config.template | 4 | ||||
-rw-r--r-- | trove/templates/mysql/replica_source.config.template | 2 | ||||
-rw-r--r-- | trove/tests/fakes/guestagent.py | 3 | ||||
-rw-r--r-- | trove/tests/unittests/common/test_template.py | 30 | ||||
-rw-r--r-- | trove/tests/unittests/guestagent/test_api.py | 3 | ||||
-rw-r--r-- | trove/tests/unittests/guestagent/test_mysql_manager.py | 7 |
17 files changed, 100 insertions, 30 deletions
diff --git a/trove/common/template.py b/trove/common/template.py index 76418412..a1cfc57d 100644 --- a/trove/common/template.py +++ b/trove/common/template.py @@ -135,3 +135,11 @@ def load_heat_template(datastore_manager): {"s_datastore_manager": datastore_manager}) LOG.error(msg) raise exception.TroveError(msg) + + +class ReplicaSourceConfigTemplate(SingleInstanceConfigTemplate): + template_name = "replica_source.config.template" + + +class ReplicaConfigTemplate(SingleInstanceConfigTemplate): + template_name = "replica.config.template" diff --git a/trove/guestagent/api.py b/trove/guestagent/api.py index bdefa8fe..bf498c59 100644 --- a/trove/guestagent/api.py +++ b/trove/guestagent/api.py @@ -325,16 +325,18 @@ class API(proxy.RpcProxy): LOG.debug("Applying overrides values %s." % overrides) self._cast("apply_overrides", overrides=overrides) - def get_replication_snapshot(self, snapshot_info=None): + def get_replication_snapshot(self, snapshot_info=None, + replica_source_config=None): LOG.debug("Retrieving replication snapshot from instance %s.", self.id) return self._call("get_replication_snapshot", AGENT_SNAPSHOT_TIMEOUT, - snapshot_info=snapshot_info) + snapshot_info=snapshot_info, + replica_source_config=replica_source_config) - def attach_replication_slave(self, snapshot, slave_config=None): + def attach_replication_slave(self, snapshot, replica_config=None): LOG.debug("Configuring instance %s to replicate from %s.", self.id, snapshot.get('master').get('id')) self._cast("attach_replication_slave", snapshot=snapshot, - slave_config=slave_config) + slave_config=replica_config) def detach_replica(self): LOG.debug("Detaching replica %s from its replication source.", self.id) diff --git a/trove/guestagent/datastore/cassandra/manager.py b/trove/guestagent/datastore/cassandra/manager.py index 21104224..ea5497b2 100644 --- a/trove/guestagent/datastore/cassandra/manager.py +++ b/trove/guestagent/datastore/cassandra/manager.py @@ -192,7 +192,8 @@ class Manager(periodic_task.PeriodicTasks): raise exception.DatastoreOperationNotSupported( operation='apply_overrides', datastore=MANAGER) - def get_replication_snapshot(self, context, snapshot_info): + def get_replication_snapshot(self, context, snapshot_info, + replica_source_config=None): raise exception.DatastoreOperationNotSupported( operation='get_replication_snapshot', datastore=MANAGER) diff --git a/trove/guestagent/datastore/couchbase/manager.py b/trove/guestagent/datastore/couchbase/manager.py index cca5d8cb..53e4dc3b 100644 --- a/trove/guestagent/datastore/couchbase/manager.py +++ b/trove/guestagent/datastore/couchbase/manager.py @@ -215,7 +215,8 @@ class Manager(periodic_task.PeriodicTasks): raise exception.DatastoreOperationNotSupported( operation='apply_overrides', datastore=MANAGER) - def get_replication_snapshot(self, context, snapshot_info): + def get_replication_snapshot(self, context, snapshot_info, + replica_source_config=None): raise exception.DatastoreOperationNotSupported( operation='get_replication_snapshot', datastore=MANAGER) diff --git a/trove/guestagent/datastore/mongodb/manager.py b/trove/guestagent/datastore/mongodb/manager.py index 61a6287e..3aaae552 100644 --- a/trove/guestagent/datastore/mongodb/manager.py +++ b/trove/guestagent/datastore/mongodb/manager.py @@ -221,7 +221,8 @@ class Manager(periodic_task.PeriodicTasks): raise exception.DatastoreOperationNotSupported( operation='apply_overrides', datastore=MANAGER) - def get_replication_snapshot(self, context, snapshot_info): + def get_replication_snapshot(self, context, snapshot_info, + replica_source_config=None): raise exception.DatastoreOperationNotSupported( operation='get_replication_snapshot', datastore=MANAGER) diff --git a/trove/guestagent/datastore/mysql/manager.py b/trove/guestagent/datastore/mysql/manager.py index 6625a30b..2e848d71 100644 --- a/trove/guestagent/datastore/mysql/manager.py +++ b/trove/guestagent/datastore/mysql/manager.py @@ -214,12 +214,14 @@ class Manager(periodic_task.PeriodicTasks): app = MySqlApp(MySqlAppStatus.get()) app.apply_overrides(overrides) - def get_replication_snapshot(self, context, snapshot_info): + def get_replication_snapshot(self, context, snapshot_info, + replica_source_config=None): LOG.debug("Getting replication snapshot.") app = MySqlApp(MySqlAppStatus.get()) replication = REPLICATION_STRATEGY_CLASS(context) - replication.enable_as_master(app, snapshot_info) + replication.enable_as_master(app, snapshot_info, + replica_source_config) snapshot_id, log_position = ( replication.snapshot_for_replication(context, app, None, @@ -264,7 +266,7 @@ class Manager(periodic_task.PeriodicTasks): try: self._validate_slave_for_replication(context, snapshot) replication = REPLICATION_STRATEGY_CLASS(context) - replication.enable_as_slave(app, snapshot) + replication.enable_as_slave(app, snapshot, slave_config) except Exception: LOG.exception("Error enabling replication.") app.status.set_status(rd_instance.ServiceStatuses.FAILED) diff --git a/trove/guestagent/datastore/mysql/service.py b/trove/guestagent/datastore/mysql/service.py index 810bdba0..24618933 100644 --- a/trove/guestagent/datastore/mysql/service.py +++ b/trove/guestagent/datastore/mysql/service.py @@ -64,7 +64,7 @@ MYSQL_SERVICE_CANDIDATES = ["mysql", "mysqld", "mysql-server"] MYSQL_BIN_CANDIDATES = ["/usr/sbin/mysqld", "/usr/libexec/mysqld"] MYCNF_OVERRIDES = "/etc/mysql/conf.d/overrides.cnf" MYCNF_OVERRIDES_TMP = "/tmp/overrides.cnf.tmp" -MYCNF_REPLMASTER = "/etc/mysql/conf.d/replication.cnf" +MYCNF_REPLMASTER = "/etc/mysql/conf.d/0replication.cnf" MYCNF_REPLMASTER_TMP = "/tmp/replication.cnf.tmp" diff --git a/trove/guestagent/datastore/redis/manager.py b/trove/guestagent/datastore/redis/manager.py index d540f3ce..b32200fc 100644 --- a/trove/guestagent/datastore/redis/manager.py +++ b/trove/guestagent/datastore/redis/manager.py @@ -215,7 +215,8 @@ class Manager(periodic_task.PeriodicTasks): raise exception.DatastoreOperationNotSupported( operation='is_root_enabled', datastore=MANAGER) - def get_replication_snapshot(self, context, snapshot_info): + def get_replication_snapshot(self, context, snapshot_info, + replica_source_config=None): raise exception.DatastoreOperationNotSupported( operation='get_replication_snapshot', datastore=MANAGER) diff --git a/trove/guestagent/strategies/replication/mysql_binlog.py b/trove/guestagent/strategies/replication/mysql_binlog.py index 604b516e..15508de6 100644 --- a/trove/guestagent/strategies/replication/mysql_binlog.py +++ b/trove/guestagent/strategies/replication/mysql_binlog.py @@ -81,13 +81,17 @@ class MysqlBinlogReplication(base.Replication): log_position = {} return snapshot_id, log_position - def enable_as_master(self, service, snapshot_info): - service.write_replication_overrides(MASTER_CONFIG) + def enable_as_master(self, service, snapshot_info, master_config): + if not master_config: + master_config = MASTER_CONFIG + service.write_replication_overrides(master_config) service.restart() service.grant_replication_privilege() - def enable_as_slave(self, service, snapshot): - service.write_replication_overrides(SLAVE_CONFIG) + def enable_as_slave(self, service, snapshot, slave_config): + if not slave_config: + slave_config = SLAVE_CONFIG + service.write_replication_overrides(slave_config) service.restart() service.change_master_for_binlog( snapshot['master']['host'], diff --git a/trove/taskmanager/manager.py b/trove/taskmanager/manager.py index 4e299ee7..1ea7b1e9 100644 --- a/trove/taskmanager/manager.py +++ b/trove/taskmanager/manager.py @@ -104,7 +104,7 @@ class Manager(periodic_task.PeriodicTasks): finally: Backup.delete(context, snapshot['dataset']['snapshot_id']) - instance_tasks.attach_replication_slave(snapshot) + instance_tasks.attach_replication_slave(snapshot, flavor) def create_instance(self, context, instance_id, name, flavor, image_id, databases, users, datastore_manager, diff --git a/trove/taskmanager/models.py b/trove/taskmanager/models.py index 6360608a..f1bce8a8 100755 --- a/trove/taskmanager/models.py +++ b/trove/taskmanager/models.py @@ -163,6 +163,18 @@ class ConfigurationMixin(object): config.render(overrides=overrides) return config + def _render_replica_source_config(self, flavor): + config = template.ReplicaSourceConfigTemplate( + self.datastore_version, flavor, self.id) + config.render() + return config + + def _render_replica_config(self, flavor): + config = template.ReplicaConfigTemplate( + self.datastore_version, flavor, self.id) + config.render() + return config + def _render_config_dict(self, flavor): config = template.SingleInstanceConfigTemplate( self.datastore_version, flavor, self.id) @@ -313,10 +325,12 @@ class FreshInstanceTasks(FreshInstance, NotifyMixin, ConfigurationMixin): LOG.exception(_("Failed to send usage create-event for " "instance %s.") % self.id) - def attach_replication_slave(self, snapshot, slave_config=None): + def attach_replication_slave(self, snapshot, flavor): LOG.debug("Calling attach_replication_slave for %s.", self.id) try: - self.guest.attach_replication_slave(snapshot, slave_config) + replica_config = self._render_replica_config(flavor) + self.guest.attach_replication_slave(snapshot, + replica_config.config_contents) except GuestError as e: msg = (_("Error attaching instance %s " "as replica.") % self.id) @@ -351,7 +365,8 @@ class FreshInstanceTasks(FreshInstance, NotifyMixin, ConfigurationMixin): 'datastore': master.datastore.name, 'datastore_version': master.datastore_version.name, }) - snapshot = master.get_replication_snapshot(snapshot_info) + snapshot = master.get_replication_snapshot( + snapshot_info, flavor=master.flavor_id) return snapshot except TroveError as e: msg = (_("Error creating replication snapshot " @@ -912,12 +927,14 @@ class BuiltInstanceTasks(BuiltInstance, NotifyMixin, ConfigurationMixin): LOG.info(_("Initiating backup for instance %s.") % self.id) self.guest.create_backup(backup_info) - def get_replication_snapshot(self, snapshot_info): + def get_replication_snapshot(self, snapshot_info, flavor): def _get_replication_snapshot(): LOG.debug("Calling get_replication_snapshot on %s.", self.id) try: - result = self.guest.get_replication_snapshot(snapshot_info) + rep_source_config = self._render_replica_source_config(flavor) + result = self.guest.get_replication_snapshot( + snapshot_info, rep_source_config.config_contents) LOG.debug("Got replication snapshot from guest successfully.") return result except (GuestError, GuestTimeout): diff --git a/trove/templates/mysql/replica.config.template b/trove/templates/mysql/replica.config.template new file mode 100644 index 00000000..a148d797 --- /dev/null +++ b/trove/templates/mysql/replica.config.template @@ -0,0 +1,4 @@ +[mysqld] +log_bin = /var/lib/mysql/mysql-bin.log +relay_log = /var/lib/mysql/mysql-relay-bin.log +read_only = true diff --git a/trove/templates/mysql/replica_source.config.template b/trove/templates/mysql/replica_source.config.template new file mode 100644 index 00000000..7aa39885 --- /dev/null +++ b/trove/templates/mysql/replica_source.config.template @@ -0,0 +1,2 @@ +[mysqld] +log_bin = /var/lib/mysql/mysql-bin.log diff --git a/trove/tests/fakes/guestagent.py b/trove/tests/fakes/guestagent.py index b01e4718..bf069e76 100644 --- a/trove/tests/fakes/guestagent.py +++ b/trove/tests/fakes/guestagent.py @@ -323,7 +323,8 @@ class FakeGuest(object): def apply_overrides(self, overrides): self.overrides = overrides - def get_replication_snapshot(self, snapshot_info): + def get_replication_snapshot(self, snapshot_info, + replica_source_config=None): self.create_backup(snapshot_info) return { 'dataset': diff --git a/trove/tests/unittests/common/test_template.py b/trove/tests/unittests/common/test_template.py index 7d5ba9da..eb151177 100644 --- a/trove/tests/unittests/common/test_template.py +++ b/trove/tests/unittests/common/test_template.py @@ -34,14 +34,18 @@ class TemplateTest(testtools.TestCase): def tearDown(self): super(TemplateTest, self).tearDown() - def validate_template(self, contents, teststr, test_flavor, server_id): - # expected query_cache_size = {{ 8 * flavor_multiplier }}M - flavor_multiplier = test_flavor['ram'] / 512 + def _find_in_template(self, contents, teststr): found_group = None for line in contents.split('\n'): m = re.search('^%s.*' % teststr, line) if m: found_group = m.group(0) + return found_group + + def validate_template(self, contents, teststr, test_flavor, server_id): + # expected query_cache_size = {{ 8 * flavor_multiplier }}M + flavor_multiplier = test_flavor['ram'] / 512 + found_group = self._find_in_template(contents, teststr) if not found_group: raise "Could not find text in template" # Check that the last group has been rendered @@ -81,6 +85,26 @@ class TemplateTest(testtools.TestCase): self.validate_template(config.render(), "hyper", {'ram': 0}, self.server_id) + def test_replica_source_config_rendering(self): + datastore = Mock(spec=DatastoreVersion) + datastore.datastore_name = 'MySql' + datastore.name = 'mysql-5.6' + datastore.manager = 'mysql' + config = template.ReplicaSourceConfigTemplate(datastore, + self.flavor_dict, + self.server_id) + self.assertTrue(self._find_in_template(config.render(), "log_bin")) + + def test_replica_config_rendering(self): + datastore = Mock(spec=DatastoreVersion) + datastore.datastore_name = 'MySql' + datastore.name = 'mysql-5.6' + datastore.manager = 'mysql' + config = template.ReplicaConfigTemplate(datastore, + self.flavor_dict, + self.server_id) + self.assertTrue(self._find_in_template(config.render(), "relay_log")) + class HeatTemplateLoadTest(testtools.TestCase): diff --git a/trove/tests/unittests/guestagent/test_api.py b/trove/tests/unittests/guestagent/test_api.py index 14e03402..7d913859 100644 --- a/trove/tests/unittests/guestagent/test_api.py +++ b/trove/tests/unittests/guestagent/test_api.py @@ -283,7 +283,8 @@ class ApiTest(testtools.TestCase): def test_get_replication_snapshot(self): exp_resp = REPLICATION_SNAPSHOT rpc.call = mock.Mock(return_value=exp_resp) - exp_msg = RpcMsgMatcher('get_replication_snapshot', 'snapshot_info') + exp_msg = RpcMsgMatcher('get_replication_snapshot', 'snapshot_info', + 'replica_source_config') # execute self.api.get_replication_snapshot({}) # verify diff --git a/trove/tests/unittests/guestagent/test_mysql_manager.py b/trove/tests/unittests/guestagent/test_mysql_manager.py index 0d103c52..3a53844a 100644 --- a/trove/tests/unittests/guestagent/test_mysql_manager.py +++ b/trove/tests/unittests/guestagent/test_mysql_manager.py @@ -281,11 +281,12 @@ class GuestAgentManagerTest(testtools.TestCase): 'log_position': log_position } - master_config = None + snapshot_info = None + replica_source_config = None # entry point replication_snapshot = ( - self.manager.get_replication_snapshot(self.context, - master_config)) + self.manager.get_replication_snapshot(self.context, snapshot_info, + replica_source_config)) # assertions self.assertEqual(expected_replication_snapshot, replication_snapshot) self.assertEqual(mock_replication.enable_as_master.call_count, 1) |