Rename node profile to flavor
Implements: blueprint rename-node-profiles-to-flavors Change-Id: Ic530041615d04878ff9586038abaf9e8dc7f707a
This commit is contained in:
parent
1126213b1a
commit
d010384fd3
@ -135,10 +135,10 @@ def transform_sizing(overcloud_sizing):
|
||||
} for (role, flavor), sizing in overcloud_sizing.items()]
|
||||
|
||||
|
||||
class NodeProfile(object):
|
||||
class Flavor(object):
|
||||
|
||||
def __init__(self, flavor):
|
||||
"""Construct node profile by wrapping flavor
|
||||
"""Construct by wrapping Nova flavor
|
||||
|
||||
:param flavor: Nova flavor
|
||||
:type flavor: novaclient.v1_1.flavors.Flavor
|
||||
@ -166,7 +166,7 @@ class NodeProfile(object):
|
||||
|
||||
@cached_property
|
||||
def extras_dict(self):
|
||||
"""Return extra parameters of node profile
|
||||
"""Return extra flavor parameters
|
||||
|
||||
:return: Nova flavor keys
|
||||
:rtype: dict
|
||||
@ -195,12 +195,12 @@ class NodeProfile(object):
|
||||
metadata=extras_dict))
|
||||
|
||||
@classmethod
|
||||
@handle_errors(_("Unable to load node profile"))
|
||||
def get(cls, request, node_profile_id):
|
||||
return cls(nova.flavor_get(request, node_profile_id))
|
||||
@handle_errors(_("Unable to load flavor."))
|
||||
def get(cls, request, flavor_id):
|
||||
return cls(nova.flavor_get(request, flavor_id))
|
||||
|
||||
@classmethod
|
||||
@handle_errors(_("Unable to retrieve node profile list."), [])
|
||||
@handle_errors(_("Unable to retrieve flavor list."), [])
|
||||
def list(cls, request):
|
||||
return [cls(item) for item in nova.flavor_list(request)]
|
||||
|
||||
@ -208,7 +208,7 @@ class NodeProfile(object):
|
||||
@memoized.memoized
|
||||
@handle_errors(_("Unable to retrieve existing servers list."), [])
|
||||
def list_deployed_ids(cls, request):
|
||||
"""Get and memoize ID's of deployed node profiles."""
|
||||
"""Get and memoize ID's of deployed flavors."""
|
||||
servers = nova.server_list(request)[0]
|
||||
return set(server.flavor['id'] for server in servers)
|
||||
|
||||
|
@ -22,7 +22,7 @@ class BasePanels(horizon.PanelGroup):
|
||||
panels = (
|
||||
'overcloud',
|
||||
'nodes',
|
||||
'node_profiles',
|
||||
'flavors',
|
||||
)
|
||||
|
||||
|
||||
|
@ -19,9 +19,9 @@ import horizon
|
||||
from tuskar_ui.infrastructure import dashboard
|
||||
|
||||
|
||||
class NodeProfiles(horizon.Panel):
|
||||
name = _("Node Profiles")
|
||||
slug = "node_profiles"
|
||||
class Flavors(horizon.Panel):
|
||||
name = _("Flavors")
|
||||
slug = "flavors"
|
||||
|
||||
|
||||
dashboard.Infrastructure.register(NodeProfiles)
|
||||
dashboard.Infrastructure.register(Flavors)
|
@ -21,43 +21,43 @@ from openstack_dashboard.dashboards.admin.flavors \
|
||||
from tuskar_ui import api
|
||||
|
||||
|
||||
class CreateNodeProfile(flavor_tables.CreateFlavor):
|
||||
verbose_name = _("New Node Profile")
|
||||
url = "horizon:infrastructure:node_profiles:create"
|
||||
class CreateFlavor(flavor_tables.CreateFlavor):
|
||||
verbose_name = _("New Flavor")
|
||||
url = "horizon:infrastructure:flavors:create"
|
||||
|
||||
|
||||
class CreateSuggestedNodeProfile(CreateNodeProfile):
|
||||
class CreateSuggestedFlavor(CreateFlavor):
|
||||
verbose_name = _("Create")
|
||||
|
||||
|
||||
class DeleteNodeProfile(flavor_tables.DeleteFlavor):
|
||||
class DeleteFlavor(flavor_tables.DeleteFlavor):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super(DeleteNodeProfile, self).__init__(**kwargs)
|
||||
super(DeleteFlavor, self).__init__(**kwargs)
|
||||
# NOTE(dtantsur): setting class attributes doesn't work
|
||||
# probably due to metaclass magic in actions
|
||||
self.data_type_singular = _("Node Profile")
|
||||
self.data_type_plural = _("Node Profiles")
|
||||
self.data_type_singular = _("Flavor")
|
||||
self.data_type_plural = _("Flavors")
|
||||
|
||||
def allowed(self, request, datum=None):
|
||||
"""Check that action is allowed on node profile
|
||||
"""Check that action is allowed on flavor
|
||||
|
||||
This is overridden method from horizon.tables.BaseAction.
|
||||
|
||||
:param datum: node profile we're operating on
|
||||
:type datum: tuskar_ui.api.NodeProfile
|
||||
:param datum: flavor we're operating on
|
||||
:type datum: tuskar_ui.api.Flavor
|
||||
"""
|
||||
if datum is not None:
|
||||
deployed_profiles = api.NodeProfile.list_deployed_ids(
|
||||
deployed_flavors = api.Flavor.list_deployed_ids(
|
||||
request, _error_default=None)
|
||||
if deployed_profiles is None or datum.id in deployed_profiles:
|
||||
if deployed_flavors is None or datum.id in deployed_flavors:
|
||||
return False
|
||||
return super(DeleteNodeProfile, self).allowed(request, datum)
|
||||
return super(DeleteFlavor, self).allowed(request, datum)
|
||||
|
||||
|
||||
class NodeProfilesTable(tables.DataTable):
|
||||
name = tables.Column('name', verbose_name=_('Node Profile'),
|
||||
link="horizon:infrastructure:node_profiles:details")
|
||||
class FlavorsTable(tables.DataTable):
|
||||
name = tables.Column('name', verbose_name=_('Flavor'),
|
||||
link="horizon:infrastructure:flavors:details")
|
||||
arch = tables.Column('cpu_arch', verbose_name=_('Architecture'))
|
||||
vcpus = tables.Column('vcpus', verbose_name=_('CPUs'))
|
||||
ram = tables.Column(flavor_tables.get_size,
|
||||
@ -73,15 +73,15 @@ class NodeProfilesTable(tables.DataTable):
|
||||
verbose_name=_('Deploy Ramdisk Image ID'))
|
||||
|
||||
class Meta:
|
||||
name = "node_profiles"
|
||||
verbose_name = _("Node Profiles")
|
||||
table_actions = (CreateNodeProfile,
|
||||
DeleteNodeProfile,
|
||||
name = "flavors"
|
||||
verbose_name = _("Flavors")
|
||||
table_actions = (CreateFlavor,
|
||||
DeleteFlavor,
|
||||
flavor_tables.FlavorFilterAction)
|
||||
row_actions = (DeleteNodeProfile,)
|
||||
row_actions = (DeleteFlavor,)
|
||||
|
||||
|
||||
class NodeProfileRolesTable(tables.DataTable):
|
||||
class FlavorRolesTable(tables.DataTable):
|
||||
name = tables.Column('name', verbose_name=_('Role Name'))
|
||||
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
@ -96,10 +96,10 @@ class NodeProfileRolesTable(tables.DataTable):
|
||||
count_getter,
|
||||
verbose_name=_("Instances Count")
|
||||
)
|
||||
super(NodeProfileRolesTable, self).__init__(request, *args, **kwargs)
|
||||
super(FlavorRolesTable, self).__init__(request, *args, **kwargs)
|
||||
|
||||
|
||||
class ProfileSuggestionsTable(tables.DataTable):
|
||||
class FlavorSuggestionsTable(tables.DataTable):
|
||||
arch = tables.Column('cpu_arch', verbose_name=_('Architecture'))
|
||||
vcpus = tables.Column('vcpus', verbose_name=_('CPUs'))
|
||||
ram = tables.Column(flavor_tables.get_size, verbose_name=_('Memory'),
|
||||
@ -108,7 +108,7 @@ class ProfileSuggestionsTable(tables.DataTable):
|
||||
verbose_name=_('Disk'), attrs={'data-type': 'size'})
|
||||
|
||||
class Meta:
|
||||
name = "profile_suggestions"
|
||||
verbose_name = _("Profile Suggestions")
|
||||
name = "flavor_suggestions"
|
||||
verbose_name = _("Flavor Suggestions")
|
||||
table_actions = ()
|
||||
row_actions = (CreateSuggestedNodeProfile,)
|
||||
row_actions = (CreateSuggestedFlavor,)
|
@ -16,41 +16,41 @@ from django.utils.translation import ugettext_lazy as _
|
||||
import horizon.tabs
|
||||
|
||||
from tuskar_ui import api
|
||||
from tuskar_ui.infrastructure.node_profiles import tables
|
||||
from tuskar_ui.infrastructure.flavors import tables
|
||||
|
||||
|
||||
def _get_unmatched_suggestions(request):
|
||||
unmatched_suggestions = []
|
||||
profile_suggestions = [ProfileSuggestion.from_node_profile(node_profile)
|
||||
for node_profile in api.NodeProfile.list(request)]
|
||||
flavor_suggestions = [FlavorSuggestion.from_flavor(flavor)
|
||||
for flavor in api.Flavor.list(request)]
|
||||
for node in api.Node.list(request):
|
||||
node_suggestion = ProfileSuggestion.from_node(node)
|
||||
for profile_suggestion in profile_suggestions:
|
||||
if profile_suggestion == node_suggestion:
|
||||
node_suggestion = FlavorSuggestion.from_node(node)
|
||||
for flavor_suggestion in flavor_suggestions:
|
||||
if flavor_suggestion == node_suggestion:
|
||||
break
|
||||
else:
|
||||
unmatched_suggestions.append(node_suggestion)
|
||||
return unmatched_suggestions
|
||||
|
||||
|
||||
def get_profile_suggestions(request):
|
||||
def get_flavor_suggestions(request):
|
||||
return set(_get_unmatched_suggestions(request))
|
||||
|
||||
|
||||
class NodeProfilesTab(horizon.tabs.TableTab):
|
||||
name = _("Node Profiles")
|
||||
slug = 'node_profiles'
|
||||
table_classes = (tables.NodeProfilesTable,)
|
||||
class FlavorsTab(horizon.tabs.TableTab):
|
||||
name = _("Flavors")
|
||||
slug = 'flavors'
|
||||
table_classes = (tables.FlavorsTable,)
|
||||
template_name = ("horizon/common/_detail_table.html")
|
||||
preload = False
|
||||
|
||||
def get_node_profiles_data(self):
|
||||
node_profiles = api.NodeProfile.list(self.request)
|
||||
node_profiles.sort(key=lambda np: (np.vcpus, np.ram, np.disk))
|
||||
return node_profiles
|
||||
def get_flavors_data(self):
|
||||
flavors = api.Flavor.list(self.request)
|
||||
flavors.sort(key=lambda np: (np.vcpus, np.ram, np.disk))
|
||||
return flavors
|
||||
|
||||
|
||||
class ProfileSuggestion(object):
|
||||
class FlavorSuggestion(object):
|
||||
"""Describe node parameters in a way that is easy to compare."""
|
||||
|
||||
def __init__(self, vcpus=None, ram=None, disk=None, cpu_arch=None,
|
||||
@ -72,11 +72,11 @@ class ProfileSuggestion(object):
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_node_profile(cls, node_profile):
|
||||
def from_flavor(cls, flavor):
|
||||
return cls(
|
||||
vcpus=node_profile.vcpus,
|
||||
ram_bytes=node_profile.ram_bytes,
|
||||
disk_bytes=node_profile.disk_bytes,
|
||||
vcpus=flavor.vcpus,
|
||||
ram_bytes=flavor.ram_bytes,
|
||||
disk_bytes=flavor.disk_bytes,
|
||||
# TODO(rdopieralski) Add architecture when available.
|
||||
)
|
||||
|
||||
@ -120,21 +120,21 @@ class ProfileSuggestion(object):
|
||||
)
|
||||
|
||||
|
||||
class ProfileSuggestionsTab(horizon.tabs.TableTab):
|
||||
name = _("Profile Suggestions")
|
||||
slug = 'profile_suggestions'
|
||||
table_classes = (tables.ProfileSuggestionsTable,)
|
||||
class FlavorSuggestionsTab(horizon.tabs.TableTab):
|
||||
name = _("Flavor Suggestions")
|
||||
slug = 'flavor_suggestions'
|
||||
table_classes = (tables.FlavorSuggestionsTable,)
|
||||
template_name = ("horizon/common/_detail_table.html")
|
||||
preload = False
|
||||
|
||||
def get_profile_suggestions_data(self):
|
||||
return list(get_profile_suggestions(self.request))
|
||||
def get_flavor_suggestions_data(self):
|
||||
return list(get_flavor_suggestions(self.request))
|
||||
|
||||
|
||||
class NodeProfileTabs(horizon.tabs.TabGroup):
|
||||
slug = 'node_profile_tabs'
|
||||
class FlavorTabs(horizon.tabs.TabGroup):
|
||||
slug = 'flavor_tabs'
|
||||
tabs = (
|
||||
NodeProfilesTab,
|
||||
ProfileSuggestionsTab,
|
||||
FlavorsTab,
|
||||
FlavorSuggestionsTab,
|
||||
)
|
||||
sticky = True
|
@ -1,9 +1,9 @@
|
||||
{% extends 'infrastructure/base.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "Create Node Profile" %}{% endblock %}
|
||||
{% block title %}{% trans "Create Flavor" %}{% endblock %}
|
||||
|
||||
{% block page_header %}
|
||||
{% include "horizon/common/_page_header.html" with title=_("Create Node Profile") %}
|
||||
{% include "horizon/common/_page_header.html" with title=_("Create Flavor") %}
|
||||
{% endblock page_header %}
|
||||
|
||||
{% block main %}
|
@ -1,9 +1,9 @@
|
||||
{% extends 'infrastructure/base.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans 'Node Profile Details' %}{% endblock %}
|
||||
{% block title %}{% trans 'Flavor Details' %}{% endblock %}
|
||||
|
||||
{% block page_header %}
|
||||
{% include 'horizon/common/_page_header.html' with title=_('Node Profile Details') %}
|
||||
{% include 'horizon/common/_page_header.html' with title=_('Flavor Details') %}
|
||||
{% endblock page_header %}
|
||||
|
||||
{% block main %}
|
||||
@ -12,13 +12,13 @@
|
||||
<h4>{% trans "Hardware Info" %}</h4>
|
||||
<dl class="clearfix">
|
||||
<dt>{% trans "Architecture" %}</dt>
|
||||
<dd>{{ node_profile.cpu_arch|default:"—" }}</dd>
|
||||
<dd>{{ flavor.cpu_arch|default:"—" }}</dd>
|
||||
<dt>{% trans "CPUs" %}</dt>
|
||||
<dd>{{ node_profile.vcpus|default:"—" }}</dd>
|
||||
<dd>{{ flavor.vcpus|default:"—" }}</dd>
|
||||
<dt>{% trans "Memory" %}</dt>
|
||||
<dd>{{ node_profile.ram_bytes|filesizeformat|default:"—" }}</dd>
|
||||
<dd>{{ flavor.ram_bytes|filesizeformat|default:"—" }}</dd>
|
||||
<dt>{% trans "Disk" %}</dt>
|
||||
<dd>{{ node_profile.disk_bytes|filesizeformat|default:"—" }}</dd>
|
||||
<dd>{{ flavor.disk_bytes|filesizeformat|default:"—" }}</dd>
|
||||
</dl>
|
||||
<h4>{% trans "Deploy Images" %}</h4>
|
||||
<dl class="clearfix">
|
@ -1,10 +1,10 @@
|
||||
{% extends 'infrastructure/base.html' %}
|
||||
{% load i18n %}
|
||||
{% load url from future %}
|
||||
{% block title %}{% trans 'Node Profiles' %}{% endblock %}
|
||||
{% block title %}{% trans 'Flavors' %}{% endblock %}
|
||||
|
||||
{% block page_header %}
|
||||
{% include 'horizon/common/_domain_page_header.html' with title=_('Node Profiles') %}
|
||||
{% include 'horizon/common/_domain_page_header.html' with title=_('Flavors') %}
|
||||
{% endblock page_header %}
|
||||
|
||||
{% block main %}
|
@ -30,10 +30,10 @@ from tuskar_ui.test.test_data import tuskar_data
|
||||
TEST_DATA = utils.TestDataContainer()
|
||||
tuskar_data.data(TEST_DATA)
|
||||
INDEX_URL = urlresolvers.reverse(
|
||||
'horizon:infrastructure:node_profiles:index')
|
||||
'horizon:infrastructure:flavors:index')
|
||||
CREATE_URL = urlresolvers.reverse(
|
||||
'horizon:infrastructure:node_profiles:create')
|
||||
DETAILS_VIEW = 'horizon:infrastructure:node_profiles:details'
|
||||
'horizon:infrastructure:flavors:create')
|
||||
DETAILS_VIEW = 'horizon:infrastructure:flavors:details'
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
@ -49,7 +49,7 @@ def _prepare_create():
|
||||
'kernel_image_id': images[0].id,
|
||||
'ramdisk_image_id': images[1].id}
|
||||
with contextlib.nested(
|
||||
patch('tuskar_ui.api.NodeProfile.create',
|
||||
patch('tuskar_ui.api.Flavor.create',
|
||||
return_value=flavor),
|
||||
patch('openstack_dashboard.api.glance.image_list_detailed',
|
||||
return_value=(TEST_DATA.glanceclient_images.list(), False)),
|
||||
@ -60,7 +60,7 @@ def _prepare_create():
|
||||
yield mocks[0], data
|
||||
|
||||
|
||||
class NodeProfilesTest(test.BaseAdminViewTests):
|
||||
class FlavorsTest(test.BaseAdminViewTests):
|
||||
|
||||
def test_index(self):
|
||||
with contextlib.nested(
|
||||
@ -74,7 +74,7 @@ class NodeProfilesTest(test.BaseAdminViewTests):
|
||||
self.assertEqual(servers_mock.call_count, 1)
|
||||
|
||||
self.assertTemplateUsed(res,
|
||||
'infrastructure/node_profiles/index.html')
|
||||
'infrastructure/flavors/index.html')
|
||||
|
||||
def test_index_recoverable_failure(self):
|
||||
with patch('openstack_dashboard.api.nova.flavor_list',
|
||||
@ -89,7 +89,7 @@ class NodeProfilesTest(test.BaseAdminViewTests):
|
||||
res = self.client.get(CREATE_URL)
|
||||
self.assertEqual(mock.call_count, 2)
|
||||
self.assertTemplateUsed(res,
|
||||
'infrastructure/node_profiles/create.html')
|
||||
'infrastructure/flavors/create.html')
|
||||
|
||||
def test_create_get_recoverable_failure(self):
|
||||
with patch('openstack_dashboard.api.glance.image_list_detailed',
|
||||
@ -119,7 +119,7 @@ class NodeProfilesTest(test.BaseAdminViewTests):
|
||||
|
||||
def test_delete_ok(self):
|
||||
flavors = TEST_DATA.novaclient_flavors.list()
|
||||
data = {'action': 'node_profiles__delete',
|
||||
data = {'action': 'flavors__delete',
|
||||
'object_ids': [flavors[0].id, flavors[1].id]}
|
||||
with contextlib.nested(
|
||||
patch('openstack_dashboard.api.nova.flavor_delete'),
|
||||
@ -146,7 +146,7 @@ class NodeProfilesTest(test.BaseAdminViewTests):
|
||||
'status': 'ACTIVE',
|
||||
'flavor': {'id': flavors[0].id}}
|
||||
)
|
||||
data = {'action': 'node_profiles__delete',
|
||||
data = {'action': 'flavors__delete',
|
||||
'object_ids': [flavors[0].id, flavors[1].id]}
|
||||
with contextlib.nested(
|
||||
patch('openstack_dashboard.api.nova.flavor_delete'),
|
||||
@ -165,14 +165,14 @@ class NodeProfilesTest(test.BaseAdminViewTests):
|
||||
self.assertEqual(server_list_mock.call_count, 1)
|
||||
|
||||
def test_details_no_overcloud(self):
|
||||
flavor = api.NodeProfile(TEST_DATA.novaclient_flavors.first())
|
||||
flavor = api.Flavor(TEST_DATA.novaclient_flavors.first())
|
||||
images = TEST_DATA.glanceclient_images.list()[:2]
|
||||
roles = TEST_DATA.tuskarclient_overcloud_roles.list()
|
||||
roles[0].flavor_id = flavor.id
|
||||
with contextlib.nested(
|
||||
patch('openstack_dashboard.api.glance.image_get',
|
||||
side_effect=images),
|
||||
patch('tuskar_ui.api.NodeProfile.get',
|
||||
patch('tuskar_ui.api.Flavor.get',
|
||||
return_value=flavor),
|
||||
patch('tuskar_ui.api.OvercloudRole.list',
|
||||
return_value=roles),
|
||||
@ -186,10 +186,10 @@ class NodeProfilesTest(test.BaseAdminViewTests):
|
||||
self.assertEqual(roles_mock.call_count, 1)
|
||||
self.assertEqual(overcloud_mock.call_count, 1)
|
||||
self.assertTemplateUsed(res,
|
||||
'infrastructure/node_profiles/details.html')
|
||||
'infrastructure/flavors/details.html')
|
||||
|
||||
def test_details(self):
|
||||
flavor = api.NodeProfile(TEST_DATA.novaclient_flavors.first())
|
||||
flavor = api.Flavor(TEST_DATA.novaclient_flavors.first())
|
||||
images = TEST_DATA.glanceclient_images.list()[:2]
|
||||
roles = TEST_DATA.tuskarclient_overcloud_roles.list()
|
||||
roles[0].flavor_id = flavor.id
|
||||
@ -197,7 +197,7 @@ class NodeProfilesTest(test.BaseAdminViewTests):
|
||||
with contextlib.nested(
|
||||
patch('openstack_dashboard.api.glance.image_get',
|
||||
side_effect=images),
|
||||
patch('tuskar_ui.api.NodeProfile.get',
|
||||
patch('tuskar_ui.api.Flavor.get',
|
||||
return_value=flavor),
|
||||
patch('tuskar_ui.api.OvercloudRole.list',
|
||||
return_value=roles),
|
||||
@ -216,4 +216,4 @@ class NodeProfilesTest(test.BaseAdminViewTests):
|
||||
self.assertEqual(count_mock.call_count, 1)
|
||||
self.assertListEqual(count_mock.call_args_list, [call(roles[0])])
|
||||
self.assertTemplateUsed(res,
|
||||
'infrastructure/node_profiles/details.html')
|
||||
'infrastructure/flavors/details.html')
|
@ -14,11 +14,11 @@
|
||||
|
||||
from django.conf import urls
|
||||
|
||||
from tuskar_ui.infrastructure.node_profiles import views
|
||||
from tuskar_ui.infrastructure.flavors import views
|
||||
|
||||
|
||||
urlpatterns = urls.patterns(
|
||||
'tuskar_ui.infrastructure.node_profiles.views',
|
||||
'tuskar_ui.infrastructure.flavors.views',
|
||||
urls.url(r'^$', views.IndexView.as_view(), name='index'),
|
||||
urls.url(r'^create/(?P<suggestion_id>[^/]+)$', views.CreateView.as_view(),
|
||||
name='create'),
|
@ -21,9 +21,9 @@ import horizon.tabs
|
||||
import horizon.workflows
|
||||
|
||||
import tuskar_ui.api
|
||||
from tuskar_ui.infrastructure.node_profiles import tables
|
||||
from tuskar_ui.infrastructure.node_profiles import tabs
|
||||
from tuskar_ui.infrastructure.node_profiles import workflows
|
||||
from tuskar_ui.infrastructure.flavors import tables
|
||||
from tuskar_ui.infrastructure.flavors import tabs
|
||||
from tuskar_ui.infrastructure.flavors import workflows
|
||||
|
||||
|
||||
def image_get(request, image_id, error_message):
|
||||
@ -35,20 +35,20 @@ def image_get(request, image_id, error_message):
|
||||
|
||||
|
||||
class IndexView(horizon.tabs.TabbedTableView):
|
||||
tab_group_class = tabs.NodeProfileTabs
|
||||
template_name = 'infrastructure/node_profiles/index.html'
|
||||
tab_group_class = tabs.FlavorTabs
|
||||
template_name = 'infrastructure/flavors/index.html'
|
||||
|
||||
|
||||
class CreateView(horizon.workflows.WorkflowView):
|
||||
workflow_class = workflows.CreateNodeProfile
|
||||
template_name = 'infrastructure/node_profiles/create.html'
|
||||
workflow_class = workflows.CreateFlavor
|
||||
template_name = 'infrastructure/flavors/create.html'
|
||||
|
||||
def get_initial(self):
|
||||
suggestion_id = self.kwargs.get('suggestion_id')
|
||||
if not suggestion_id:
|
||||
return super(CreateView, self).get_initial()
|
||||
node = tuskar_ui.api.Node.get(self.request, suggestion_id)
|
||||
suggestion = tabs.ProfileSuggestion.from_node(node)
|
||||
suggestion = tabs.FlavorSuggestion.from_node(node)
|
||||
return {
|
||||
'name': suggestion.name,
|
||||
'vcpus': suggestion.vcpus,
|
||||
@ -59,25 +59,25 @@ class CreateView(horizon.workflows.WorkflowView):
|
||||
|
||||
|
||||
class DetailView(horizon.tables.DataTableView):
|
||||
table_class = tables.NodeProfileRolesTable
|
||||
template_name = 'infrastructure/node_profiles/details.html'
|
||||
error_redirect = reverse_lazy('horizon:infrastructure:node_profiles:index')
|
||||
table_class = tables.FlavorRolesTable
|
||||
template_name = 'infrastructure/flavors/details.html'
|
||||
error_redirect = reverse_lazy('horizon:infrastructure:flavors:index')
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(DetailView, self).get_context_data(**kwargs)
|
||||
context['node_profile'] = tuskar_ui.api.NodeProfile.get(
|
||||
context['flavor'] = tuskar_ui.api.Flavor.get(
|
||||
self.request,
|
||||
kwargs.get('flavor_id'),
|
||||
_error_redirect=self.error_redirect
|
||||
)
|
||||
context['kernel_image'] = image_get(
|
||||
self.request,
|
||||
context['node_profile'].kernel_image_id,
|
||||
context['flavor'].kernel_image_id,
|
||||
error_message=_("Cannot get kernel image details")
|
||||
)
|
||||
context['ramdisk_image'] = image_get(
|
||||
self.request,
|
||||
context['node_profile'].ramdisk_image_id,
|
||||
context['flavor'].ramdisk_image_id,
|
||||
error_message=_("Cannot get ramdisk image details")
|
||||
)
|
||||
return context
|
@ -24,7 +24,7 @@ from openstack_dashboard.dashboards.admin.flavors \
|
||||
from tuskar_ui import api
|
||||
|
||||
|
||||
class CreateNodeProfileAction(flavor_workflows.CreateFlavorInfoAction):
|
||||
class CreateFlavorAction(flavor_workflows.CreateFlavorInfoAction):
|
||||
arch = fields.ChoiceField(choices=(('i386', 'i386'), ('amd64', 'amd64')),
|
||||
label=_("Architecture"))
|
||||
kernel_image_id = fields.ChoiceField(choices=(),
|
||||
@ -33,7 +33,7 @@ class CreateNodeProfileAction(flavor_workflows.CreateFlavorInfoAction):
|
||||
label=_("Deploy Ramdisk Image"))
|
||||
|
||||
def __init__(self, *args, **kwrds):
|
||||
super(CreateNodeProfileAction, self).__init__(*args, **kwrds)
|
||||
super(CreateFlavorAction, self).__init__(*args, **kwrds)
|
||||
try:
|
||||
kernel_images = glance.image_list_detailed(
|
||||
self.request,
|
||||
@ -62,14 +62,14 @@ class CreateNodeProfileAction(flavor_workflows.CreateFlavorInfoAction):
|
||||
del self.fields['flavor_id']
|
||||
|
||||
class Meta:
|
||||
name = _("Node Profile")
|
||||
name = _("Flavor")
|
||||
# FIXME(dtantsur): maybe better help text?
|
||||
help_text = _("From here you can create a new "
|
||||
"node profile to organize instance resources.")
|
||||
"flavor to organize instance resources.")
|
||||
|
||||
|
||||
class CreateNodeProfileStep(workflows.Step):
|
||||
action_class = CreateNodeProfileAction
|
||||
class CreateFlavorStep(workflows.Step):
|
||||
action_class = CreateFlavorAction
|
||||
contributes = ("name",
|
||||
"vcpus",
|
||||
"memory_mb",
|
||||
@ -79,18 +79,18 @@ class CreateNodeProfileStep(workflows.Step):
|
||||
"ramdisk_image_id")
|
||||
|
||||
|
||||
class CreateNodeProfile(flavor_workflows.CreateFlavor):
|
||||
slug = "create_node_profile"
|
||||
name = _("Create Node Profile")
|
||||
finalize_button_name = _("Create Node Profile")
|
||||
success_message = _('Created new node profile "%s".')
|
||||
failure_message = _('Unable to create node profile "%s".')
|
||||
success_url = "horizon:infrastructure:node_profiles:index"
|
||||
default_steps = (CreateNodeProfileStep,)
|
||||
class CreateFlavor(flavor_workflows.CreateFlavor):
|
||||
slug = "create_flavor"
|
||||
name = _("Create Flavor")
|
||||
finalize_button_name = _("Create Flavor")
|
||||
success_message = _('Created new flavor "%s".')
|
||||
failure_message = _('Unable to create flavor "%s".')
|
||||
success_url = "horizon:infrastructure:flavors:index"
|
||||
default_steps = (CreateFlavorStep,)
|
||||
|
||||
def handle(self, request, data):
|
||||
try:
|
||||
self.object = api.NodeProfile.create(
|
||||
self.object = api.Flavor.create(
|
||||
request,
|
||||
name=data['name'],
|
||||
memory=data['memory_mb'],
|
||||
@ -101,6 +101,6 @@ class CreateNodeProfile(flavor_workflows.CreateFlavor):
|
||||
ramdisk_image_id=data['ramdisk_image_id']
|
||||
)
|
||||
except Exception:
|
||||
exceptions.handle(request, _("Unable to create node profile"))
|
||||
exceptions.handle(request, _("Unable to create flavor"))
|
||||
return False
|
||||
return True
|
@ -63,7 +63,7 @@ class OvercloudRoleForm(horizon.forms.SelfHandlingForm):
|
||||
widget=django.forms.TextInput(
|
||||
attrs={'readonly': 'readonly', 'disabled': 'disabled'}))
|
||||
flavor_id = django.forms.ChoiceField(
|
||||
label=_("Node Profile"), required=False, choices=())
|
||||
label=_("Flavor"), required=False, choices=())
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(OvercloudRoleForm, self).__init__(*args, **kwargs)
|
||||
|
@ -5,7 +5,7 @@
|
||||
<table class="table">
|
||||
<tr>
|
||||
<th>{% trans "Name" %}</th>
|
||||
<th>{% trans "Node profiles" %}</th>
|
||||
<th>{% trans "Flavors" %}</th>
|
||||
<th>{% trans "Nodes" %}</th>
|
||||
{% if show_change %}
|
||||
<th>{% trans "Change" %}</th>
|
||||
@ -33,9 +33,9 @@
|
||||
(<a
|
||||
href="{% url 'horizon:infrastructure:overcloud:role_edit' role_id %}"
|
||||
class="ajax-modal"
|
||||
>{% trans "Add a node profile" %}</a>)
|
||||
>{% trans "Add a flavor" %}</a>)
|
||||
{% else %}
|
||||
({% trans "No node profile" %})
|
||||
({% trans "No flavor" %})
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
|
@ -12,7 +12,7 @@
|
||||
<div class="span12">
|
||||
<p><strong>{% blocktrans count counter=nodes|length %}{{ counter }} instance{% plural %}{{ counter }} instances{% endblocktrans %}</strong></p>
|
||||
<dl>
|
||||
<dt>{% trans 'Node Profile' %}</dt>
|
||||
<dt>{% trans 'Flavor' %}</dt>
|
||||
<dd><em>{{ flavor.name }}</em> {{ flavor.get_keys.cpu_arch }} | {{ flavor.vcpus }} {% trans "CPU" %} | {{ flavor.ram }} {% trans "MB RAM" %} | {{ flavor.disk }} {% trans "GB HDD" %}</dd>
|
||||
<dt>{% trans 'Image' %}</dt>
|
||||
<dd>{{ image_name }}</dd>
|
||||
|
@ -172,7 +172,7 @@ class OvercloudRoleView(horizon_tables.DataTableView,
|
||||
try:
|
||||
context['flavor'] = nova.flavor_get(self.request, role.flavor_id)
|
||||
except Exception:
|
||||
msg = _('Unable to retrieve node profile.')
|
||||
msg = _('Unable to retrieve flavor.')
|
||||
horizon.exceptions.handle(self.request, msg)
|
||||
return context
|
||||
|
||||
|
@ -29,7 +29,7 @@ class Step(undeployed_overview.Step):
|
||||
template_name = 'infrastructure/overcloud/scale_node_counts.html'
|
||||
|
||||
def prepare_action_context(self, request, context):
|
||||
for (role_id, profile_id), count in context['role_counts'].items():
|
||||
name = 'count__%s__%s' % (role_id, profile_id)
|
||||
for (role_id, flavor_id), count in context['role_counts'].items():
|
||||
name = 'count__%s__%s' % (role_id, flavor_id)
|
||||
context[name] = count
|
||||
return context
|
||||
|
@ -22,17 +22,17 @@ from tuskar_ui import api
|
||||
import tuskar_ui.forms
|
||||
|
||||
|
||||
def get_role_id_and_profile_id_from_field_name(field_name):
|
||||
"""Extract the ids of overcloud role and node profile from the field
|
||||
def get_role_id_and_flavor_id_from_field_name(field_name):
|
||||
"""Extract the ids of overcloud role and flavor from the field
|
||||
name.
|
||||
"""
|
||||
_count, role_id, profile_id = field_name.split('__', 2)
|
||||
return role_id, profile_id
|
||||
_count, role_id, flavor_id = field_name.split('__', 2)
|
||||
return role_id, flavor_id
|
||||
|
||||
|
||||
def get_field_name_from_role_id_and_profile_id(role_id, profile_id=''):
|
||||
"""Compose the ids of overcloud role and node profile into a field name."""
|
||||
return 'count__%s__%s' % (role_id, profile_id)
|
||||
def get_field_name_from_role_id_and_flavor_id(role_id, flavor_id=''):
|
||||
"""Compose the ids of overcloud role and flavor into a field name."""
|
||||
return 'count__%s__%s' % (role_id, flavor_id)
|
||||
|
||||
|
||||
class Action(horizon.workflows.Action):
|
||||
@ -40,7 +40,7 @@ class Action(horizon.workflows.Action):
|
||||
slug = 'undeployed_overview'
|
||||
name = _("Overview")
|
||||
|
||||
def _get_profile_names(self):
|
||||
def _get_flavor_names(self):
|
||||
# Get all flavors in one call, instead of getting them one by one.
|
||||
try:
|
||||
flavors = horizon_api.nova.flavor_list(self.request, None)
|
||||
@ -50,21 +50,21 @@ class Action(horizon.workflows.Action):
|
||||
flavors = []
|
||||
return dict((str(flavor.id), flavor.name) for flavor in flavors)
|
||||
|
||||
def _get_profiles(self, role, profile_names):
|
||||
# TODO(rdopieralski) Get a list of hardware profiles for each
|
||||
# role here, when we support multiple profiles per role.
|
||||
if role.flavor_id and role.flavor_id in profile_names:
|
||||
profiles = [(
|
||||
def _get_flavors(self, role, flavor_names):
|
||||
# TODO(rdopieralski) Get a list of flavors for each
|
||||
# role here, when we support multiple flavors per role.
|
||||
if role.flavor_id and role.flavor_id in flavor_names:
|
||||
flavors = [(
|
||||
role.flavor_id,
|
||||
profile_names[role.flavor_id],
|
||||
flavor_names[role.flavor_id],
|
||||
)]
|
||||
else:
|
||||
profiles = []
|
||||
return profiles
|
||||
flavors = []
|
||||
return flavors
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Action, self).__init__(*args, **kwargs)
|
||||
profile_names = self._get_profile_names()
|
||||
flavor_names = self._get_flavor_names()
|
||||
for role in self._get_roles():
|
||||
if role.name == 'Controller':
|
||||
initial = 1
|
||||
@ -72,16 +72,16 @@ class Action(horizon.workflows.Action):
|
||||
else:
|
||||
initial = 0
|
||||
attrs = {}
|
||||
profiles = self._get_profiles(role, profile_names)
|
||||
if not profiles:
|
||||
name = get_field_name_from_role_id_and_profile_id(str(role.id))
|
||||
flavors = self._get_flavors(role, flavor_names)
|
||||
if not flavors:
|
||||
name = get_field_name_from_role_id_and_flavor_id(str(role.id))
|
||||
attrs = {'readonly': 'readonly'}
|
||||
self.fields[name] = django.forms.IntegerField(
|
||||
label='', initial=initial, min_value=initial,
|
||||
widget=tuskar_ui.forms.NumberPickerInput(attrs=attrs))
|
||||
for profile_id, label in profiles:
|
||||
name = get_field_name_from_role_id_and_profile_id(
|
||||
str(role.id), profile_id)
|
||||
for flavor_id, label in flavors:
|
||||
name = get_field_name_from_role_id_and_flavor_id(
|
||||
str(role.id), flavor_id)
|
||||
self.fields[name] = django.forms.IntegerField(
|
||||
label=label, initial=initial, min_value=initial,
|
||||
widget=tuskar_ui.forms.NumberPickerInput(attrs=attrs))
|
||||
@ -93,7 +93,7 @@ class Action(horizon.workflows.Action):
|
||||
role.id,
|
||||
role.name,
|
||||
list(tuskar_ui.forms.fieldset(
|
||||
self, prefix=get_field_name_from_role_id_and_profile_id(
|
||||
self, prefix=get_field_name_from_role_id_and_flavor_id(
|
||||
str(role.id)))),
|
||||
)
|
||||
|
||||
@ -106,10 +106,10 @@ class Action(horizon.workflows.Action):
|
||||
for key, value in self.cleaned_data.iteritems():
|
||||
if not key.startswith('count_'):
|
||||
continue
|
||||
role_id, profile = get_role_id_and_profile_id_from_field_name(key)
|
||||
if int(value) and not profile:
|
||||
role_id, flavor = get_role_id_and_flavor_id_from_field_name(key)
|
||||
if int(value) and not flavor:
|
||||
raise django.forms.ValidationError(
|
||||
_("Can't deploy nodes without a node profile assigned."))
|
||||
_("Can't deploy nodes without a flavor assigned."))
|
||||
return self.cleaned_data
|
||||
|
||||
|
||||
@ -128,7 +128,7 @@ class Step(horizon.workflows.Step):
|
||||
for key, value in data.iteritems():
|
||||
if not key.startswith('count_'):
|
||||
continue
|
||||
count, role_id, profile = key.split('__', 2)
|
||||
counts[role_id, profile] = int(value)
|
||||
count, role_id, flavor = key.split('__', 2)
|
||||
counts[role_id, flavor] = int(value)
|
||||
context['role_counts'] = counts
|
||||
return context
|
||||
|
@ -421,8 +421,8 @@ def data(TEST):
|
||||
'name': 'Block Storage Image'})
|
||||
TEST.glanceclient_images.add(image_1, image_2, image_3, image_4)
|
||||
|
||||
# Nova flavors aka node profiles
|
||||
# Do not include fields irrelevant for node profiles
|
||||
# Nova flavors
|
||||
# Do not include fields irrelevant for our usage
|
||||
TEST.novaclient_flavors = test_data_utils.TestDataContainer()
|
||||
flavor_1 = flavors.Flavor(
|
||||
flavors.FlavorManager(None),
|
||||
|
Loading…
x
Reference in New Issue
Block a user