summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIccha Sethi <iccha.sethi@rackspace.com>2014-09-17 14:41:19 -0500
committerNikhil Manchanda <SlickNik@gmail.com>2014-10-01 03:31:48 -0700
commit957f72bf311d5c76c5e2f5fffdee4aebd12c56a5 (patch)
treee043a0c23efac4b909fc80aeb691922330fe7c2f
parentba3a43f2c5d3233118f0cb152a299c29e6018d36 (diff)
downloadtrove-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.py8
-rw-r--r--trove/guestagent/api.py10
-rw-r--r--trove/guestagent/datastore/cassandra/manager.py3
-rw-r--r--trove/guestagent/datastore/couchbase/manager.py3
-rw-r--r--trove/guestagent/datastore/mongodb/manager.py3
-rw-r--r--trove/guestagent/datastore/mysql/manager.py8
-rw-r--r--trove/guestagent/datastore/mysql/service.py2
-rw-r--r--trove/guestagent/datastore/redis/manager.py3
-rw-r--r--trove/guestagent/strategies/replication/mysql_binlog.py12
-rw-r--r--trove/taskmanager/manager.py2
-rwxr-xr-xtrove/taskmanager/models.py27
-rw-r--r--trove/templates/mysql/replica.config.template4
-rw-r--r--trove/templates/mysql/replica_source.config.template2
-rw-r--r--trove/tests/fakes/guestagent.py3
-rw-r--r--trove/tests/unittests/common/test_template.py30
-rw-r--r--trove/tests/unittests/guestagent/test_api.py3
-rw-r--r--trove/tests/unittests/guestagent/test_mysql_manager.py7
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)