Add support for Trove Replication
Added initial support for replication. Changed launch dialog to have an Advanced tab where you can select a master instance for replication Display replication information in details view Added support for Detach Change-Id: I2c90d5be0f47c07fe9049a685fbf7a36a2585e0e Implements: blueprint trove-replication-v1-support
This commit is contained in:
parent
9d32c18ac8
commit
d719e8e9f6
@ -57,7 +57,8 @@ def instance_delete(request, instance_id):
|
|||||||
|
|
||||||
def instance_create(request, name, volume, flavor, databases=None,
|
def instance_create(request, name, volume, flavor, databases=None,
|
||||||
users=None, restore_point=None, nics=None,
|
users=None, restore_point=None, nics=None,
|
||||||
datastore=None, datastore_version=None):
|
datastore=None, datastore_version=None,
|
||||||
|
replica_of=None):
|
||||||
# TODO(dklyle): adding conditional to support trove without volume
|
# TODO(dklyle): adding conditional to support trove without volume
|
||||||
# support for now until API supports checking for volume support
|
# support for now until API supports checking for volume support
|
||||||
if volume > 0:
|
if volume > 0:
|
||||||
@ -73,7 +74,8 @@ def instance_create(request, name, volume, flavor, databases=None,
|
|||||||
restorePoint=restore_point,
|
restorePoint=restore_point,
|
||||||
nics=nics,
|
nics=nics,
|
||||||
datastore=datastore,
|
datastore=datastore,
|
||||||
datastore_version=datastore_version)
|
datastore_version=datastore_version,
|
||||||
|
replica_of=replica_of)
|
||||||
|
|
||||||
|
|
||||||
def instance_resize_volume(request, instance_id, size):
|
def instance_resize_volume(request, instance_id, size):
|
||||||
@ -93,6 +95,11 @@ def instance_restart(request, instance_id):
|
|||||||
return troveclient(request).instances.restart(instance_id)
|
return troveclient(request).instances.restart(instance_id)
|
||||||
|
|
||||||
|
|
||||||
|
def instance_detach_replica(request, instance_id):
|
||||||
|
return troveclient(request).instances.edit(instance_id,
|
||||||
|
detach_replica_source=True)
|
||||||
|
|
||||||
|
|
||||||
def database_list(request, instance_id):
|
def database_list(request, instance_id):
|
||||||
return troveclient(request).databases.list(instance_id)
|
return troveclient(request).databases.list(instance_id)
|
||||||
|
|
||||||
|
@ -83,6 +83,34 @@ class RestartInstance(tables.BatchAction):
|
|||||||
api.trove.instance_restart(request, obj_id)
|
api.trove.instance_restart(request, obj_id)
|
||||||
|
|
||||||
|
|
||||||
|
class DetachReplica(tables.BatchAction):
|
||||||
|
@staticmethod
|
||||||
|
def action_present(count):
|
||||||
|
return ungettext_lazy(
|
||||||
|
u"Detach Replica",
|
||||||
|
u"Detach Replicas",
|
||||||
|
count
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def action_past(count):
|
||||||
|
return ungettext_lazy(
|
||||||
|
u"Replica Detached",
|
||||||
|
u"Replicas Detached",
|
||||||
|
count
|
||||||
|
)
|
||||||
|
|
||||||
|
name = "detach_replica"
|
||||||
|
classes = ('btn-danger', 'btn-detach-replica')
|
||||||
|
|
||||||
|
def allowed(self, request, instance=None):
|
||||||
|
return (instance.status in ACTIVE_STATES
|
||||||
|
and hasattr(instance, 'replica_of'))
|
||||||
|
|
||||||
|
def action(self, request, obj_id):
|
||||||
|
api.trove.instance_detach_replica(request, obj_id)
|
||||||
|
|
||||||
|
|
||||||
class DeleteUser(tables.DeleteAction):
|
class DeleteUser(tables.DeleteAction):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def action_present(count):
|
def action_present(count):
|
||||||
@ -289,6 +317,7 @@ class InstancesTable(tables.DataTable):
|
|||||||
ResizeVolume,
|
ResizeVolume,
|
||||||
ResizeInstance,
|
ResizeInstance,
|
||||||
RestartInstance,
|
RestartInstance,
|
||||||
|
DetachReplica,
|
||||||
TerminateInstance)
|
TerminateInstance)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
{% load i18n sizeformat %}
|
{% load i18n sizeformat %}
|
||||||
|
{% load url from future %}
|
||||||
|
|
||||||
<h3>{% trans "Instance Overview" %}</h3>
|
<h3>{% trans "Instance Overview" %}</h3>
|
||||||
|
|
||||||
@ -40,3 +41,29 @@
|
|||||||
|
|
||||||
{% block connection_info %}
|
{% block connection_info %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
{% if instance.replica_of or instance.replicas %}
|
||||||
|
<div class="specs row detail">
|
||||||
|
<h4>{% trans "Replication" %}</h4>
|
||||||
|
<hr class="header_rule">
|
||||||
|
<dl>
|
||||||
|
{% if instance.replica_of %}
|
||||||
|
<dt>{% trans "Is a Replica Of" %}</dt>
|
||||||
|
<dd>
|
||||||
|
{% url 'horizon:project:databases:detail' instance.replica_of.id as instance_url %}
|
||||||
|
<a href="{{ instance_url }}">{{ instance.replica_of.id }}</a>
|
||||||
|
</dd>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if instance.replicas %}
|
||||||
|
<dt>{% trans "Replicas" %}</dt>
|
||||||
|
{% for replica in instance.replicas %}
|
||||||
|
<dd>
|
||||||
|
{% url 'horizon:project:databases:detail' replica.id as instance_url %}
|
||||||
|
<a href="{{ instance_url }}">{{ replica.id }}</a>
|
||||||
|
</dd>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
<p>{% blocktrans %}Optionally choose to create this database using a previous backup, or as a replica of another database instance.{% endblocktrans %}</p>
|
@ -1,4 +1,4 @@
|
|||||||
{% load i18n horizon humanize %}
|
{% load i18n %}
|
||||||
|
|
||||||
<p>{% blocktrans %}Specify the details for launching an instance.{% endblocktrans %}</p>
|
<p>{% blocktrans %}Specify the details for launching an instance.{% endblocktrans %}</p>
|
||||||
<p>{% blocktrans %}<strong>Please note:</strong> The value specified in the Volume Size field should be greater than 0, however, some configurations do not support specifying volume size. If specifying the volume size results in an error stating volume support is not enabled, enter 0.{% endblocktrans %}</p>
|
<p>{% blocktrans %}<strong>Please note:</strong> The value specified in the Volume Size field should be greater than 0, however, some configurations do not support specifying volume size. If specifying the volume size results in an error stating volume support is not enabled, enter 0.{% endblocktrans %}</p>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
{% load i18n horizon humanize %}
|
{% load i18n %}
|
||||||
|
|
||||||
<h4>{% trans "Initial Databases" %}</h4>
|
<h4>{% trans "Initial Databases" %}</h4>
|
||||||
<p>{% trans "Optionally provide a comma separated list of databases to create:" %}</p>
|
<p>{% trans "Optionally provide a comma separated list of databases to create:" %}</p>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
{% load i18n horizon %}
|
{% load i18n %}
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
{% blocktrans %}
|
{% blocktrans %}
|
||||||
|
@ -1,4 +0,0 @@
|
|||||||
{% load i18n horizon humanize %}
|
|
||||||
|
|
||||||
<p>{% blocktrans %}Create this database from a previous backup.{% endblocktrans %}</p>
|
|
||||||
|
|
@ -121,18 +121,32 @@ class DatabaseTests(test.TestCase):
|
|||||||
|
|
||||||
@test.create_stubs({
|
@test.create_stubs({
|
||||||
api.trove: ('flavor_list', 'backup_list',
|
api.trove: ('flavor_list', 'backup_list',
|
||||||
'datastore_list', 'datastore_version_list')})
|
'datastore_list', 'datastore_version_list',
|
||||||
|
'instance_list'),
|
||||||
|
api.neutron: ('network_list',)})
|
||||||
def test_launch_instance(self):
|
def test_launch_instance(self):
|
||||||
api.trove.flavor_list(IsA(http.HttpRequest))\
|
api.trove.flavor_list(IsA(http.HttpRequest)).AndReturn(
|
||||||
.AndReturn(self.flavors.list())
|
self.flavors.list())
|
||||||
api.trove.backup_list(IsA(http.HttpRequest))\
|
api.trove.backup_list(IsA(http.HttpRequest)).AndReturn(
|
||||||
.AndReturn(self.database_backups.list())
|
self.database_backups.list())
|
||||||
|
api.trove.instance_list(IsA(http.HttpRequest)).AndReturn(
|
||||||
|
self.databases.list())
|
||||||
# Mock datastores
|
# Mock datastores
|
||||||
api.trove.datastore_list(IsA(http.HttpRequest))\
|
api.trove.datastore_list(IsA(http.HttpRequest)).AndReturn(
|
||||||
.AndReturn(self.datastores.list())
|
self.datastores.list())
|
||||||
# Mock datastore versions
|
# Mock datastore versions
|
||||||
api.trove.datastore_version_list(IsA(http.HttpRequest), IsA(str))\
|
api.trove.datastore_version_list(IsA(http.HttpRequest), IsA(str)).\
|
||||||
.AndReturn(self.datastore_versions.list())
|
AndReturn(self.datastore_versions.list())
|
||||||
|
|
||||||
|
api.neutron.network_list(IsA(http.HttpRequest),
|
||||||
|
tenant_id=self.tenant.id,
|
||||||
|
shared=False).AndReturn(
|
||||||
|
self.networks.list()[:1])
|
||||||
|
|
||||||
|
api.neutron.network_list(IsA(http.HttpRequest),
|
||||||
|
shared=True).AndReturn(
|
||||||
|
self.networks.list()[1:])
|
||||||
|
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
res = self.client.get(LAUNCH_URL)
|
res = self.client.get(LAUNCH_URL)
|
||||||
self.assertTemplateUsed(res, 'project/databases/launch.html')
|
self.assertTemplateUsed(res, 'project/databases/launch.html')
|
||||||
@ -165,7 +179,8 @@ class DatabaseTests(test.TestCase):
|
|||||||
|
|
||||||
@test.create_stubs({
|
@test.create_stubs({
|
||||||
api.trove: ('flavor_list', 'backup_list', 'instance_create',
|
api.trove: ('flavor_list', 'backup_list', 'instance_create',
|
||||||
'datastore_list', 'datastore_version_list'),
|
'datastore_list', 'datastore_version_list',
|
||||||
|
'instance_list'),
|
||||||
api.neutron: ('network_list',)})
|
api.neutron: ('network_list',)})
|
||||||
def test_create_simple_instance(self):
|
def test_create_simple_instance(self):
|
||||||
api.trove.flavor_list(IsA(http.HttpRequest)).AndReturn(
|
api.trove.flavor_list(IsA(http.HttpRequest)).AndReturn(
|
||||||
@ -174,6 +189,9 @@ class DatabaseTests(test.TestCase):
|
|||||||
api.trove.backup_list(IsA(http.HttpRequest)).AndReturn(
|
api.trove.backup_list(IsA(http.HttpRequest)).AndReturn(
|
||||||
self.database_backups.list())
|
self.database_backups.list())
|
||||||
|
|
||||||
|
api.trove.instance_list(IsA(http.HttpRequest)).AndReturn(
|
||||||
|
self.databases.list())
|
||||||
|
|
||||||
# Mock datastores
|
# Mock datastores
|
||||||
api.trove.datastore_list(IsA(http.HttpRequest))\
|
api.trove.datastore_list(IsA(http.HttpRequest))\
|
||||||
.AndReturn(self.datastores.list())
|
.AndReturn(self.datastores.list())
|
||||||
@ -203,6 +221,7 @@ class DatabaseTests(test.TestCase):
|
|||||||
datastore=IsA(unicode),
|
datastore=IsA(unicode),
|
||||||
datastore_version=IsA(unicode),
|
datastore_version=IsA(unicode),
|
||||||
restore_point=None,
|
restore_point=None,
|
||||||
|
replica_of=None,
|
||||||
users=None,
|
users=None,
|
||||||
nics=nics).AndReturn(self.databases.first())
|
nics=nics).AndReturn(self.databases.first())
|
||||||
|
|
||||||
@ -220,7 +239,8 @@ class DatabaseTests(test.TestCase):
|
|||||||
|
|
||||||
@test.create_stubs({
|
@test.create_stubs({
|
||||||
api.trove: ('flavor_list', 'backup_list', 'instance_create',
|
api.trove: ('flavor_list', 'backup_list', 'instance_create',
|
||||||
'datastore_list', 'datastore_version_list'),
|
'datastore_list', 'datastore_version_list',
|
||||||
|
'instance_list'),
|
||||||
api.neutron: ('network_list',)})
|
api.neutron: ('network_list',)})
|
||||||
def test_create_simple_instance_exception(self):
|
def test_create_simple_instance_exception(self):
|
||||||
trove_exception = self.exceptions.nova
|
trove_exception = self.exceptions.nova
|
||||||
@ -230,6 +250,9 @@ class DatabaseTests(test.TestCase):
|
|||||||
api.trove.backup_list(IsA(http.HttpRequest)).AndReturn(
|
api.trove.backup_list(IsA(http.HttpRequest)).AndReturn(
|
||||||
self.database_backups.list())
|
self.database_backups.list())
|
||||||
|
|
||||||
|
api.trove.instance_list(IsA(http.HttpRequest)).AndReturn(
|
||||||
|
self.databases.list())
|
||||||
|
|
||||||
# Mock datastores
|
# Mock datastores
|
||||||
api.trove.datastore_list(IsA(http.HttpRequest))\
|
api.trove.datastore_list(IsA(http.HttpRequest))\
|
||||||
.AndReturn(self.datastores.list())
|
.AndReturn(self.datastores.list())
|
||||||
@ -259,6 +282,7 @@ class DatabaseTests(test.TestCase):
|
|||||||
datastore=IsA(unicode),
|
datastore=IsA(unicode),
|
||||||
datastore_version=IsA(unicode),
|
datastore_version=IsA(unicode),
|
||||||
restore_point=None,
|
restore_point=None,
|
||||||
|
replica_of=None,
|
||||||
users=None,
|
users=None,
|
||||||
nics=nics).AndRaise(trove_exception)
|
nics=nics).AndRaise(trove_exception)
|
||||||
|
|
||||||
@ -445,3 +469,67 @@ class DatabaseTests(test.TestCase):
|
|||||||
res = self.client.post(url, post)
|
res = self.client.post(url, post)
|
||||||
self.assertNoFormErrors(res)
|
self.assertNoFormErrors(res)
|
||||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||||
|
|
||||||
|
@test.create_stubs({
|
||||||
|
api.trove: ('flavor_list', 'backup_list', 'instance_create',
|
||||||
|
'datastore_list', 'datastore_version_list',
|
||||||
|
'instance_list', 'instance_get'),
|
||||||
|
api.neutron: ('network_list',)})
|
||||||
|
def test_create_replica_instance(self):
|
||||||
|
api.trove.flavor_list(IsA(http.HttpRequest)).AndReturn(
|
||||||
|
self.flavors.list())
|
||||||
|
|
||||||
|
api.trove.backup_list(IsA(http.HttpRequest)).AndReturn(
|
||||||
|
self.database_backups.list())
|
||||||
|
|
||||||
|
api.trove.instance_list(IsA(http.HttpRequest)).AndReturn(
|
||||||
|
self.databases.list())
|
||||||
|
|
||||||
|
api.trove.datastore_list(IsA(http.HttpRequest))\
|
||||||
|
.AndReturn(self.datastores.list())
|
||||||
|
|
||||||
|
api.trove.datastore_version_list(IsA(http.HttpRequest),
|
||||||
|
IsA(str))\
|
||||||
|
.AndReturn(self.datastore_versions.list())
|
||||||
|
|
||||||
|
api.neutron.network_list(IsA(http.HttpRequest),
|
||||||
|
tenant_id=self.tenant.id,
|
||||||
|
shared=False).\
|
||||||
|
AndReturn(self.networks.list()[:1])
|
||||||
|
|
||||||
|
api.neutron.network_list(IsA(http.HttpRequest),
|
||||||
|
shared=True).\
|
||||||
|
AndReturn(self.networks.list()[1:])
|
||||||
|
|
||||||
|
nics = [{"net-id": self.networks.first().id, "v4-fixed-ip": ''}]
|
||||||
|
|
||||||
|
api.trove.instance_get(IsA(http.HttpRequest), IsA(unicode))\
|
||||||
|
.AndReturn(self.databases.first())
|
||||||
|
|
||||||
|
# Actual create database call
|
||||||
|
api.trove.instance_create(
|
||||||
|
IsA(http.HttpRequest),
|
||||||
|
IsA(unicode),
|
||||||
|
IsA(int),
|
||||||
|
IsA(unicode),
|
||||||
|
databases=None,
|
||||||
|
datastore=IsA(unicode),
|
||||||
|
datastore_version=IsA(unicode),
|
||||||
|
restore_point=None,
|
||||||
|
replica_of=self.databases.first().id,
|
||||||
|
users=None,
|
||||||
|
nics=nics).AndReturn(self.databases.first())
|
||||||
|
|
||||||
|
self.mox.ReplayAll()
|
||||||
|
post = {
|
||||||
|
'name': "MyDB",
|
||||||
|
'volume': '1',
|
||||||
|
'flavor': 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
|
||||||
|
'network': self.networks.first().id,
|
||||||
|
'datastore': 'mysql,5.5',
|
||||||
|
'initial_state': 'master',
|
||||||
|
'master': self.databases.first().id
|
||||||
|
}
|
||||||
|
|
||||||
|
res = self.client.post(LAUNCH_URL, post)
|
||||||
|
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||||
|
@ -223,15 +223,41 @@ class InitializeDatabase(workflows.Step):
|
|||||||
contributes = ["databases", 'user', 'password', 'host']
|
contributes = ["databases", 'user', 'password', 'host']
|
||||||
|
|
||||||
|
|
||||||
class RestoreAction(workflows.Action):
|
class AdvancedAction(workflows.Action):
|
||||||
backup = forms.ChoiceField(label=_("Backup"),
|
initial_state = forms.ChoiceField(
|
||||||
required=False,
|
label=_('Source for Initial State'),
|
||||||
help_text=_('Select a backup to restore'))
|
required=False,
|
||||||
|
help_text=_("Choose initial state."),
|
||||||
|
choices=[
|
||||||
|
('', _('None')),
|
||||||
|
('backup', _('Restore from Backup')),
|
||||||
|
('master', _('Replicate from Instance'))],
|
||||||
|
widget=forms.Select(attrs={
|
||||||
|
'class': 'switchable',
|
||||||
|
'data-slug': 'initial_state'
|
||||||
|
}))
|
||||||
|
backup = forms.ChoiceField(
|
||||||
|
label=_('Backup Name'),
|
||||||
|
required=False,
|
||||||
|
help_text=_('Select a backup to restore'),
|
||||||
|
widget=forms.Select(attrs={
|
||||||
|
'class': 'switched',
|
||||||
|
'data-switch-on': 'initial_state',
|
||||||
|
'data-initial_state-backup': _('Backup Name')
|
||||||
|
}))
|
||||||
|
master = forms.ChoiceField(
|
||||||
|
label=_('Master Instance Name'),
|
||||||
|
required=False,
|
||||||
|
help_text=_('Select a master instance'),
|
||||||
|
widget=forms.Select(attrs={
|
||||||
|
'class': 'switched',
|
||||||
|
'data-switch-on': 'initial_state',
|
||||||
|
'data-initial_state-master': _('Master Instance Name')
|
||||||
|
}))
|
||||||
|
|
||||||
class Meta(object):
|
class Meta(object):
|
||||||
name = _("Restore From Backup")
|
name = _("Advanced")
|
||||||
permissions = ('openstack.services.object-store',)
|
help_text_template = "project/databases/_launch_advanced_help.html"
|
||||||
help_text_template = "project/databases/_launch_restore_help.html"
|
|
||||||
|
|
||||||
def populate_backup_choices(self, request, context):
|
def populate_backup_choices(self, request, context):
|
||||||
try:
|
try:
|
||||||
@ -247,23 +273,60 @@ class RestoreAction(workflows.Action):
|
|||||||
choices.insert(0, ("", _("No backups available")))
|
choices.insert(0, ("", _("No backups available")))
|
||||||
return choices
|
return choices
|
||||||
|
|
||||||
def clean_backup(self):
|
def populate_master_choices(self, request, context):
|
||||||
backup = self.cleaned_data['backup']
|
try:
|
||||||
if backup:
|
instances = api.trove.instance_list(request)
|
||||||
try:
|
choices = [(i.id, i.name) for i in
|
||||||
# Make sure the user is not "hacking" the form
|
instances if i.status == 'ACTIVE']
|
||||||
# and that they have access to this backup_id
|
except Exception:
|
||||||
LOG.debug("Obtaining backups")
|
choices = []
|
||||||
bkup = api.trove.backup_get(self.request, backup)
|
|
||||||
self.cleaned_data['backup'] = bkup.id
|
if choices:
|
||||||
except Exception:
|
choices.insert(0, ("", _("Select instance")))
|
||||||
raise forms.ValidationError(_("Unable to find backup!"))
|
else:
|
||||||
return backup
|
choices.insert(0, ("", _("No instances available")))
|
||||||
|
return choices
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
cleaned_data = super(AdvancedAction, self).clean()
|
||||||
|
|
||||||
|
initial_state = cleaned_data.get("initial_state")
|
||||||
|
|
||||||
|
if initial_state == 'backup':
|
||||||
|
backup = self.cleaned_data['backup']
|
||||||
|
if backup:
|
||||||
|
try:
|
||||||
|
bkup = api.trove.backup_get(self.request, backup)
|
||||||
|
self.cleaned_data['backup'] = bkup.id
|
||||||
|
except Exception:
|
||||||
|
raise forms.ValidationError(_("Unable to find backup!"))
|
||||||
|
else:
|
||||||
|
raise forms.ValidationError(_("A backup must be selected!"))
|
||||||
|
|
||||||
|
cleaned_data['master'] = None
|
||||||
|
elif initial_state == 'master':
|
||||||
|
master = self.cleaned_data['master']
|
||||||
|
if master:
|
||||||
|
try:
|
||||||
|
api.trove.instance_get(self.request, master)
|
||||||
|
except Exception:
|
||||||
|
raise forms.ValidationError(
|
||||||
|
_("Unable to find master instance!"))
|
||||||
|
else:
|
||||||
|
raise forms.ValidationError(
|
||||||
|
_("A master instance must be selected!"))
|
||||||
|
|
||||||
|
cleaned_data['backup'] = None
|
||||||
|
else:
|
||||||
|
cleaned_data['master'] = None
|
||||||
|
cleaned_data['backup'] = None
|
||||||
|
|
||||||
|
return cleaned_data
|
||||||
|
|
||||||
|
|
||||||
class RestoreBackup(workflows.Step):
|
class Advanced(workflows.Step):
|
||||||
action_class = RestoreAction
|
action_class = AdvancedAction
|
||||||
contributes = ['backup']
|
contributes = ['backup', 'master']
|
||||||
|
|
||||||
|
|
||||||
class LaunchInstance(workflows.Workflow):
|
class LaunchInstance(workflows.Workflow):
|
||||||
@ -276,7 +339,7 @@ class LaunchInstance(workflows.Workflow):
|
|||||||
default_steps = (SetInstanceDetails,
|
default_steps = (SetInstanceDetails,
|
||||||
SetNetwork,
|
SetNetwork,
|
||||||
InitializeDatabase,
|
InitializeDatabase,
|
||||||
RestoreBackup)
|
Advanced)
|
||||||
|
|
||||||
def __init__(self, request=None, context_seed=None, entry_point=None,
|
def __init__(self, request=None, context_seed=None, entry_point=None,
|
||||||
*args, **kwargs):
|
*args, **kwargs):
|
||||||
@ -332,11 +395,12 @@ class LaunchInstance(workflows.Workflow):
|
|||||||
"{name=%s, volume=%s, flavor=%s, "
|
"{name=%s, volume=%s, flavor=%s, "
|
||||||
"datastore=%s, datastore_version=%s, "
|
"datastore=%s, datastore_version=%s, "
|
||||||
"dbs=%s, users=%s, "
|
"dbs=%s, users=%s, "
|
||||||
"backups=%s, nics=%s}",
|
"backups=%s, nics=%s, replica_of=%s}",
|
||||||
context['name'], context['volume'], context['flavor'],
|
context['name'], context['volume'], context['flavor'],
|
||||||
datastore, datastore_version,
|
datastore, datastore_version,
|
||||||
self._get_databases(context), self._get_users(context),
|
self._get_databases(context), self._get_users(context),
|
||||||
self._get_backup(context), self._get_nics(context))
|
self._get_backup(context), self._get_nics(context),
|
||||||
|
context.get('master'))
|
||||||
api.trove.instance_create(request,
|
api.trove.instance_create(request,
|
||||||
context['name'],
|
context['name'],
|
||||||
context['volume'],
|
context['volume'],
|
||||||
@ -346,7 +410,8 @@ class LaunchInstance(workflows.Workflow):
|
|||||||
databases=self._get_databases(context),
|
databases=self._get_databases(context),
|
||||||
users=self._get_users(context),
|
users=self._get_users(context),
|
||||||
restore_point=self._get_backup(context),
|
restore_point=self._get_backup(context),
|
||||||
nics=self._get_nics(context))
|
nics=self._get_nics(context),
|
||||||
|
replica_of=context.get('master'))
|
||||||
return True
|
return True
|
||||||
except Exception:
|
except Exception:
|
||||||
exceptions.handle(request)
|
exceptions.handle(request)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user