Add support for Trove create database

Added a table action on the databases table that displays a create
database dialog.

Co-Authored-By: Duk Loi <duk@tesora.com>
Change-Id: I092629080987bcdd8c54e052be2f7fa9b84259a0
Implements: blueprint trove-create-database-support
This commit is contained in:
Matt Van Dijk 2016-01-14 10:28:26 -05:00 committed by Duk Loi
parent 7386d021e7
commit c6e74073ca
9 changed files with 173 additions and 7 deletions

View File

@ -155,6 +155,16 @@ def database_list(request, instance_id):
return troveclient(request).databases.list(instance_id)
def database_create(request, instance_id, db_name, character_set=None,
collation=None):
database = {'name': db_name}
if collation:
database['collate'] = collation
if character_set:
database['character_set'] = character_set
return troveclient(request).databases.create(instance_id, [database])
def database_delete(request, instance_id, db_name):
return troveclient(request).databases.delete(instance_id, db_name)

View File

@ -24,6 +24,33 @@ from horizon.utils import validators
from trove_dashboard import api
class CreateDatabaseForm(forms.SelfHandlingForm):
instance_id = forms.CharField(widget=forms.HiddenInput())
name = forms.CharField(label=_("Name"))
character_set = forms.CharField(
label=_("Character Set"), required=False,
help_text=_("Optional character set for the database."))
collation = forms.CharField(
label=_("Collation"), required=False,
help_text=_("Optional collation type for the database."))
def handle(self, request, data):
instance = data.get('instance_id')
try:
api.trove.database_create(request, instance, data['name'],
character_set=data['character_set'],
collation=data['collation'])
messages.success(request,
_('Created database "%s".') % data['name'])
except Exception as e:
redirect = reverse("horizon:project:databases:detail",
args=(instance,))
exceptions.handle(request, _('Unable to create database. %s') %
e.message, redirect=redirect)
return True
class ResizeVolumeForm(forms.SelfHandlingForm):
instance_id = forms.CharField(widget=forms.HiddenInput())
orig_size = forms.IntegerField(

View File

@ -306,6 +306,30 @@ class DeleteUser(tables.DeleteAction):
api.trove.user_delete(request, datum.instance.id, datum.name)
class CreateDatabase(tables.LinkAction):
name = "create_database"
verbose_name = _("Create Database")
url = "horizon:project:databases:create_database"
classes = ("ajax-modal",)
icon = "plus"
def allowed(self, request, database=None):
instance = self.table.kwargs['instance']
return (instance.status in ACTIVE_STATES and
has_database_add_perm(request))
def get_link_url(self, datum=None):
instance_id = self.table.kwargs['instance_id']
return urlresolvers.reverse(self.url, args=[instance_id])
def has_database_add_perm(request):
perms = getattr(settings, 'TROVE_ADD_DATABASE_PERMS', [])
if perms:
return request.user.has_perms(perms)
return True
class DeleteDatabase(tables.DeleteAction):
@staticmethod
def action_present(count):
@ -533,7 +557,7 @@ class DatabaseTable(tables.DataTable):
class Meta(object):
name = "databases"
verbose_name = _("Databases")
table_actions = [DeleteDatabase]
table_actions = [CreateDatabase, DeleteDatabase]
row_actions = [DeleteDatabase]
def get_object_id(self, datum):

View File

@ -12,7 +12,6 @@
# License for the specific language governing permissions and limitations
# under the License.
from django.conf import settings
from django import template
from django.utils.translation import ugettext_lazy as _
@ -96,10 +95,7 @@ class DatabaseTab(tabs.TableTab):
return data
def allowed(self, request):
perms = getattr(settings, 'TROVE_ADD_DATABASE_PERMS', [])
if perms:
return request.user.has_perms(perms)
return True
return tables.has_database_add_perm(request)
class BackupsTab(tabs.TableTab):

View File

@ -0,0 +1,8 @@
{% extends "horizon/common/_modal_form.html" %}
{% load i18n %}
{% block modal-body-right %}
<p>{% trans "Specify the name of the new database." %}</p>
<p>{% trans "Optionally provide a character set and collation for the database." %}</p>
{% endblock %}

View File

@ -0,0 +1,6 @@
{% extends 'base.html' %}
{% block main %}
{% include "project/databases/_create_database.html" %}
{% endblock %}

View File

@ -18,7 +18,7 @@ import logging
import django
from django.core.urlresolvers import reverse
from django import http
from django.utils import unittest
import unittest
from mox3.mox import IsA # noqa
import six
@ -333,6 +333,73 @@ class DatabaseTests(test.TestCase):
database = self.databases.list()[1]
self._test_details(database, with_designate=True)
def test_create_database(self):
database = self.databases.first()
url = reverse('horizon:project:databases:create_database',
args=[database.id])
res = self.client.get(url)
self.assertTemplateUsed(res, 'project/databases/create_database.html')
@test.create_stubs({api.trove: ('database_create',)})
def test_create_new_database(self):
new_database = {
"status": "ACTIVE",
"updated": "2013-08-12T22:00:09",
"name": "NewDB",
"links": [],
"created": "2013-08-12T22:00:03",
"ip": [
"10.0.0.3",
],
"volume": {
"used": 0.13,
"size": 1,
},
"flavor": {
"id": "1",
"links": [],
},
"datastore": {
"type": "mysql",
"version": "5.5"
},
"id": "12345678-73db-4e23-b52e-368937d72719",
}
api.trove.database_create(
IsA(http.HttpRequest), u'id', u'NewDB', character_set=u'',
collation=u'').AndReturn(new_database)
self.mox.ReplayAll()
url = reverse('horizon:project:databases:create_database',
args=['id'])
post = {
'method': 'CreateDatabaseForm',
'instance_id': 'id',
'name': 'NewDB'}
res = self.client.post(url, post)
self.assertNoFormErrors(res)
self.assertMessageCount(success=1)
@test.create_stubs({api.trove: ('database_create',)})
def test_create_new_database_exception(self):
api.trove.database_create(
IsA(http.HttpRequest), u'id', u'NewDB', character_set=u'',
collation=u'').AndRaise(self.exceptions.trove)
self.mox.ReplayAll()
url = reverse('horizon:project:databases:create_database',
args=['id'])
post = {
'method': 'CreateDatabaseForm',
'instance_id': 'id',
'name': 'NewDB'}
res = self.client.post(url, post)
self.assertEqual(res.status_code, 302)
@test.create_stubs(
{api.trove: ('instance_get', 'flavor_get', 'users_list',
'user_list_access', 'user_delete')})

View File

@ -37,4 +37,6 @@ urlpatterns = patterns(
name='edit_user'),
url(USERS % 'access_detail', views.AccessDetailView.as_view(),
name='access_detail'),
url(INSTANCES % 'create_database', views.CreateDatabaseView.as_view(),
name='create_database'),
)

View File

@ -248,6 +248,32 @@ class DetailView(horizon_tabs.TabbedTableView):
return reverse('horizon:project:databases:index')
class CreateDatabaseView(horizon_forms.ModalFormView):
form_class = forms.CreateDatabaseForm
form_id = "create_database_form"
modal_header = _("Create Database")
modal_id = "create_database_modal"
template_name = 'project/databases/create_database.html'
submit_label = _("Create Database")
submit_url = 'horizon:project:databases:create_database'
success_url = 'horizon:project:databases:detail'
def get_success_url(self):
return reverse(self.success_url,
args=(self.kwargs['instance_id'],))
def get_context_data(self, **kwargs):
context = super(CreateDatabaseView, self).get_context_data(**kwargs)
context['instance_id'] = self.kwargs['instance_id']
args = (self.kwargs['instance_id'],)
context['submit_url'] = reverse(self.submit_url, args=args)
return context
def get_initial(self):
instance_id = self.kwargs['instance_id']
return {'instance_id': instance_id}
class ResizeVolumeView(horizon_forms.ModalFormView):
form_class = forms.ResizeVolumeForm
template_name = 'project/databases/resize_volume.html'