Merge "Support a host create operation"
This commit is contained in:
commit
43309a8532
|
@ -118,6 +118,12 @@ def host_get(request, host_id):
|
|||
return Host(host)
|
||||
|
||||
|
||||
def host_create(request, name, **kwargs):
|
||||
"""Create a host."""
|
||||
host = blazarclient(request).host.create(name, **kwargs)
|
||||
return Host(host)
|
||||
|
||||
|
||||
def host_delete(request, host_id):
|
||||
"""Delete a host."""
|
||||
blazarclient(request).host.delete(host_id)
|
||||
|
|
|
@ -18,6 +18,14 @@ from horizon.templatetags import sizeformat
|
|||
from blazar_dashboard import api
|
||||
|
||||
|
||||
class CreateHosts(tables.LinkAction):
|
||||
name = "create"
|
||||
verbose_name = _("Create Hosts")
|
||||
url = "horizon:admin:hosts:create"
|
||||
classes = ("ajax-modal",)
|
||||
icon = "plus"
|
||||
|
||||
|
||||
class DeleteHost(tables.DeleteAction):
|
||||
name = "delete"
|
||||
data_type_singular = _("Host")
|
||||
|
@ -57,5 +65,5 @@ class HostsTable(tables.DataTable):
|
|||
class Meta(object):
|
||||
name = "hosts"
|
||||
verbose_name = _("Hosts")
|
||||
table_actions = (DeleteHost,)
|
||||
table_actions = (CreateHosts, DeleteHost,)
|
||||
row_actions = (DeleteHost,)
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "Create Hosts" %}{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
{% include 'horizon/common/_workflow.html' %}
|
||||
{% endblock %}
|
|
@ -13,8 +13,9 @@
|
|||
from django.core.urlresolvers import reverse
|
||||
from django import http
|
||||
from mox3.mox import IsA
|
||||
from openstack_dashboard import api
|
||||
|
||||
from blazar_dashboard import api
|
||||
from blazar_dashboard import api as blazar_api
|
||||
from blazar_dashboard.test import helpers as test
|
||||
|
||||
import logging
|
||||
|
@ -24,13 +25,15 @@ INDEX_TEMPLATE = 'admin/hosts/index.html'
|
|||
INDEX_URL = reverse('horizon:admin:hosts:index')
|
||||
DETAIL_TEMPLATE = 'admin/hosts/detail.html'
|
||||
DETAIL_URL_BASE = 'horizon:admin:hosts:detail'
|
||||
CREATE_URL = reverse('horizon:admin:hosts:create')
|
||||
CREATE_TEMPLATE = 'admin/hosts/create.html'
|
||||
|
||||
|
||||
class HostsTests(test.BaseAdminViewTests):
|
||||
@test.create_stubs({api.client: ('host_list',)})
|
||||
@test.create_stubs({blazar_api.client: ('host_list',)})
|
||||
def test_index(self):
|
||||
hosts = self.hosts.list()
|
||||
api.client.host_list(IsA(http.HttpRequest)).AndReturn(hosts)
|
||||
blazar_api.client.host_list(IsA(http.HttpRequest)).AndReturn(hosts)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
res = self.client.get(INDEX_URL)
|
||||
|
@ -39,9 +42,9 @@ class HostsTests(test.BaseAdminViewTests):
|
|||
self.assertContains(res, 'compute-1')
|
||||
self.assertContains(res, 'compute-2')
|
||||
|
||||
@test.create_stubs({api.client: ('host_list',)})
|
||||
@test.create_stubs({blazar_api.client: ('host_list',)})
|
||||
def test_index_no_hosts(self):
|
||||
api.client.host_list(IsA(http.HttpRequest)).AndReturn(())
|
||||
blazar_api.client.host_list(IsA(http.HttpRequest)).AndReturn(())
|
||||
self.mox.ReplayAll()
|
||||
|
||||
res = self.client.get(INDEX_URL)
|
||||
|
@ -49,9 +52,9 @@ class HostsTests(test.BaseAdminViewTests):
|
|||
self.assertNoMessages(res)
|
||||
self.assertContains(res, 'No items to display')
|
||||
|
||||
@test.create_stubs({api.client: ('host_list',)})
|
||||
@test.create_stubs({blazar_api.client: ('host_list',)})
|
||||
def test_index_error(self):
|
||||
api.client.host_list(
|
||||
blazar_api.client.host_list(
|
||||
IsA(http.HttpRequest)
|
||||
).AndRaise(self.exceptions.blazar)
|
||||
self.mox.ReplayAll()
|
||||
|
@ -60,11 +63,11 @@ class HostsTests(test.BaseAdminViewTests):
|
|||
self.assertTemplateUsed(res, INDEX_TEMPLATE)
|
||||
self.assertMessageCount(res, error=1)
|
||||
|
||||
@test.create_stubs({api.client: ('host_get',)})
|
||||
@test.create_stubs({blazar_api.client: ('host_get',)})
|
||||
def test_host_detail(self):
|
||||
host = self.hosts.get(hypervisor_hostname='compute-1')
|
||||
api.client.host_get(IsA(http.HttpRequest),
|
||||
host['id']).AndReturn(host)
|
||||
blazar_api.client.host_get(IsA(http.HttpRequest),
|
||||
host['id']).AndReturn(host)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
res = self.client.get(reverse(DETAIL_URL_BASE, args=[host['id']]))
|
||||
|
@ -72,10 +75,10 @@ class HostsTests(test.BaseAdminViewTests):
|
|||
self.assertContains(res, 'compute-1')
|
||||
self.assertContains(res, 'ex1')
|
||||
|
||||
@test.create_stubs({api.client: ('host_get',)})
|
||||
@test.create_stubs({blazar_api.client: ('host_get',)})
|
||||
def test_host_detail_error(self):
|
||||
api.client.host_get(IsA(http.HttpRequest),
|
||||
'invalid').AndRaise(self.exceptions.blazar)
|
||||
blazar_api.client.host_get(IsA(http.HttpRequest),
|
||||
'invalid').AndRaise(self.exceptions.blazar)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
res = self.client.get(reverse(DETAIL_URL_BASE, args=['invalid']))
|
||||
|
@ -83,12 +86,35 @@ class HostsTests(test.BaseAdminViewTests):
|
|||
self.assertMessageCount(error=1)
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
@test.create_stubs({api.client: ('host_list', 'host_delete')})
|
||||
@test.create_stubs({blazar_api.client: ('host_list', 'host_create',),
|
||||
api.nova: ('host_list',)})
|
||||
def test_create_hosts(self):
|
||||
blazar_api.client.host_list(IsA(http.HttpRequest)
|
||||
).AndReturn([])
|
||||
api.nova.host_list(IsA(http.HttpRequest)
|
||||
).AndReturn(self.novahosts.list())
|
||||
host_names = [h.host_name for h in self.novahosts.list()]
|
||||
for host_name in host_names:
|
||||
blazar_api.client.host_create(
|
||||
IsA(http.HttpRequest),
|
||||
name=host_name,
|
||||
).AndReturn([])
|
||||
self.mox.ReplayAll()
|
||||
form_data = {
|
||||
'select_hosts_role_member': host_names
|
||||
}
|
||||
|
||||
res = self.client.post(CREATE_URL, form_data)
|
||||
self.assertNoFormErrors(res)
|
||||
self.assertMessageCount(success=(len(host_names) + 1))
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
@test.create_stubs({blazar_api.client: ('host_list', 'host_delete')})
|
||||
def test_delete_host(self):
|
||||
hosts = self.hosts.list()
|
||||
host = self.hosts.get(hypervisor_hostname='compute-1')
|
||||
api.client.host_list(IsA(http.HttpRequest)).AndReturn(hosts)
|
||||
api.client.host_delete(IsA(http.HttpRequest), host['id'])
|
||||
blazar_api.client.host_list(IsA(http.HttpRequest)).AndReturn(hosts)
|
||||
blazar_api.client.host_delete(IsA(http.HttpRequest), host['id'])
|
||||
self.mox.ReplayAll()
|
||||
|
||||
action = 'hosts__delete__%s' % host['id']
|
||||
|
@ -97,13 +123,14 @@ class HostsTests(test.BaseAdminViewTests):
|
|||
self.assertMessageCount(success=1)
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
@test.create_stubs({api.client: ('host_list', 'host_delete')})
|
||||
@test.create_stubs({blazar_api.client: ('host_list', 'host_delete')})
|
||||
def test_delete_host_error(self):
|
||||
hosts = self.hosts.list()
|
||||
host = self.hosts.get(hypervisor_hostname='compute-1')
|
||||
api.client.host_list(IsA(http.HttpRequest)).AndReturn(hosts)
|
||||
api.client.host_delete(IsA(http.HttpRequest),
|
||||
host['id']).AndRaise(self.exceptions.blazar)
|
||||
blazar_api.client.host_list(IsA(http.HttpRequest)).AndReturn(hosts)
|
||||
blazar_api.client.host_delete(
|
||||
IsA(http.HttpRequest),
|
||||
host['id']).AndRaise(self.exceptions.blazar)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
action = 'hosts__delete__%s' % host['id']
|
||||
|
|
|
@ -17,5 +17,6 @@ from blazar_dashboard.content.hosts import views
|
|||
|
||||
urlpatterns = [
|
||||
url(r'^$', views.IndexView.as_view(), name='index'),
|
||||
url(r'^create/$', views.CreateView.as_view(), name='create'),
|
||||
url(r'^(?P<host_id>[^/]+)/$', views.DetailView.as_view(), name='detail')
|
||||
]
|
||||
|
|
|
@ -14,10 +14,12 @@ from django.utils.translation import ugettext_lazy as _
|
|||
from horizon import exceptions
|
||||
from horizon import tables
|
||||
from horizon import tabs
|
||||
from horizon import workflows
|
||||
|
||||
from blazar_dashboard import api
|
||||
from blazar_dashboard.content.hosts import tables as project_tables
|
||||
from blazar_dashboard.content.hosts import tabs as project_tabs
|
||||
from blazar_dashboard.content.hosts import workflows as project_workflows
|
||||
|
||||
|
||||
class IndexView(tables.DataTableView):
|
||||
|
@ -37,3 +39,9 @@ class IndexView(tables.DataTableView):
|
|||
class DetailView(tabs.TabView):
|
||||
tab_group_class = project_tabs.HostDetailTabs
|
||||
template_name = 'admin/hosts/detail.html'
|
||||
|
||||
|
||||
class CreateView(workflows.WorkflowView):
|
||||
workflow_class = project_workflows.CreateHostsWorkflow
|
||||
template_name = 'admin/hosts/create.html'
|
||||
page_title = _("Create Hosts")
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import logging
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from horizon import exceptions
|
||||
from horizon import forms
|
||||
from horizon import messages
|
||||
from horizon import workflows
|
||||
from openstack_dashboard import api
|
||||
|
||||
from blazar_dashboard import api as blazar_api
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SelectHostsAction(workflows.MembershipAction):
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
super(SelectHostsAction, self).__init__(request, *args, **kwargs)
|
||||
err_msg = _('Unable to get the available hosts')
|
||||
|
||||
default_role_field_name = self.get_default_role_field_name()
|
||||
self.fields[default_role_field_name] = forms.CharField(required=False)
|
||||
self.fields[default_role_field_name].initial = 'member'
|
||||
|
||||
field_name = self.get_member_field_name('member')
|
||||
self.fields[field_name] = forms.MultipleChoiceField(required=False)
|
||||
|
||||
try:
|
||||
nova_hosts = api.nova.host_list(request)
|
||||
blazar_hosts = blazar_api.client.host_list(request)
|
||||
except Exception:
|
||||
exceptions.handle(request, err_msg)
|
||||
|
||||
nova_hostnames = []
|
||||
for host in nova_hosts:
|
||||
if (host.host_name not in nova_hostnames
|
||||
and host.service == u'compute'):
|
||||
nova_hostnames.append(host.host_name)
|
||||
|
||||
blazar_hostnames = []
|
||||
for host in blazar_hosts:
|
||||
if host.hypervisor_hostname not in blazar_hostnames:
|
||||
blazar_hostnames.append(host.hypervisor_hostname)
|
||||
|
||||
host_names = list(set(nova_hostnames) - set(blazar_hostnames))
|
||||
host_names.sort()
|
||||
|
||||
self.fields[field_name].choices = \
|
||||
[(host_name, host_name) for host_name in host_names]
|
||||
|
||||
self.fields[field_name].initial = None
|
||||
|
||||
class Meta(object):
|
||||
name = _("Select Hosts")
|
||||
slug = "select_hosts"
|
||||
|
||||
|
||||
class AddExtraCapsAction(workflows.Action):
|
||||
# TODO(hiro-kobayashi): Implement this class
|
||||
class Meta(object):
|
||||
name = _("Extra Capabilities")
|
||||
help_text = _("Not supported yet.")
|
||||
slug = "add_extra_caps"
|
||||
|
||||
|
||||
class SelectHostsStep(workflows.UpdateMembersStep):
|
||||
action_class = SelectHostsAction
|
||||
help_text = _("Select hosts to create")
|
||||
available_list_title = _("All available hosts")
|
||||
members_list_title = _("Selected hosts")
|
||||
no_available_text = _("No host found.")
|
||||
no_members_text = _("No host selected.")
|
||||
show_roles = False
|
||||
contributes = ("names",)
|
||||
|
||||
def contribute(self, data, context):
|
||||
if data:
|
||||
member_field_name = self.get_member_field_name('member')
|
||||
context['names'] = data.get(member_field_name, [])
|
||||
return context
|
||||
|
||||
|
||||
class AddExtraCapsStep(workflows.Step):
|
||||
# TODO(hiro-kobayashi): Implement this class
|
||||
action_class = AddExtraCapsAction
|
||||
help_text = _("Add extra capabilities")
|
||||
show_roles = False
|
||||
|
||||
|
||||
class CreateHostsWorkflow(workflows.Workflow):
|
||||
slug = "create_hosts"
|
||||
name = _("Create Hosts")
|
||||
finalize_button_name = _("Create Hosts")
|
||||
success_url = 'horizon:admin:hosts:index'
|
||||
default_steps = (SelectHostsStep, AddExtraCapsStep)
|
||||
|
||||
def handle(self, request, context):
|
||||
try:
|
||||
for name in context['names']:
|
||||
blazar_api.client.host_create(request, name=name)
|
||||
messages.success(request, _('Host %s was successfully '
|
||||
'created.') % name)
|
||||
except Exception:
|
||||
exceptions.handle(request, _('Unable to create host.'))
|
||||
return False
|
||||
|
||||
return True
|
|
@ -168,6 +168,15 @@ host_sample2 = {
|
|||
}
|
||||
|
||||
|
||||
class DummyNovaHost(object):
|
||||
def __init__(self, host_name, service):
|
||||
self.host_name = host_name
|
||||
self.service = service
|
||||
|
||||
novahost_sample1 = DummyNovaHost('compute-1', 'compute')
|
||||
novahost_sample2 = DummyNovaHost('compute-2', 'compute')
|
||||
|
||||
|
||||
def data(TEST):
|
||||
TEST.leases = utils.TestDataContainer()
|
||||
|
||||
|
@ -178,3 +187,8 @@ def data(TEST):
|
|||
|
||||
TEST.hosts.add(api.client.Host(host_sample1))
|
||||
TEST.hosts.add(api.client.Host(host_sample2))
|
||||
|
||||
TEST.novahosts = utils.TestDataContainer()
|
||||
|
||||
TEST.novahosts.add(novahost_sample1)
|
||||
TEST.novahosts.add(novahost_sample2)
|
||||
|
|
Loading…
Reference in New Issue