Enable zuul unit tests for stx-gui

Enable flake8 and fix tox errors resulting from that.

Story: 2003863
Task: 27930

Change-Id: Ia331856cbd6862d3c9341435450a391a7c2a2fef
Signed-off-by: Kristine Bujold <kristine.bujold@windriver.com>
This commit is contained in:
Kristine Bujold 2018-11-14 13:50:08 -05:00
parent f1013be39f
commit 182d8ff492
69 changed files with 1491 additions and 1477 deletions

View File

@ -158,6 +158,7 @@ man_pages = [
# dir menu entry, description, category) # dir menu entry, description, category)
texinfo_documents = [ texinfo_documents = [
(master_doc, 'stx-gui', 'stx-gui Documentation', (master_doc, 'stx-gui', 'stx-gui Documentation',
author, 'stx-gui', 'StarlingX Horizon plugins for new StarlingX services.', author, 'stx-gui',
'StarlingX Horizon plugins for new StarlingX services.',
'Miscellaneous'), 'Miscellaneous'),
] ]

View File

@ -1,2 +1,2 @@
SRC_DIR="starlingx-dashboard" SRC_DIR="starlingx-dashboard"
TIS_PATCH_VER=16 TIS_PATCH_VER=17

View File

@ -11,19 +11,19 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
# #
# Copyright (c) 2017 Wind River Systems, Inc. # Copyright (c) 2017-2018 Wind River Systems, Inc.
# #
from starlingx_dashboard.api import base from starlingx_dashboard.api import base
from starlingx_dashboard.api import dc_manager from starlingx_dashboard.api import dc_manager
from starlingx_dashboard.api import fm
from starlingx_dashboard.api import neutron from starlingx_dashboard.api import neutron
from starlingx_dashboard.api import nova from starlingx_dashboard.api import nova
from starlingx_dashboard.api import fm from starlingx_dashboard.api import patch
from starlingx_dashboard.api import sysinv from starlingx_dashboard.api import sysinv
from starlingx_dashboard.api import vim from starlingx_dashboard.api import vim
from starlingx_dashboard.api import patch
# TODO (ediardo): cleanup the imports below
__all__ = [ __all__ = [
"base", "base",
"dc_manager", "dc_manager",

View File

@ -3,9 +3,7 @@
# #
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# #
import six
from django.conf import settings from django.conf import settings
from horizon import exceptions
from openstack_dashboard.api import base from openstack_dashboard.api import base

View File

@ -4,7 +4,13 @@
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# #
from openstack_dashboard.api.neutron import * from openstack_dashboard.api.neutron import neutronclient
from openstack_dashboard.api.neutron import PortForwardingRule
from openstack_dashboard.api.neutron import ProviderNetwork
from openstack_dashboard.api.neutron import ProviderNetworkRange
from openstack_dashboard.api.neutron import ProviderNetworkType
from openstack_dashboard.api.neutron import ProviderTenantNetwork
from openstack_dashboard.api.neutron import QoSPolicy
def provider_network_type_list(request, **params): def provider_network_type_list(request, **params):

View File

@ -8,7 +8,8 @@ from novaclient.v2 import wrs_pci
from novaclient.v2 import wrs_providernets from novaclient.v2 import wrs_providernets
from openstack_dashboard.api import base from openstack_dashboard.api import base
from openstack_dashboard.api.nova import * from openstack_dashboard.api.nova import nova_exceptions
from openstack_dashboard.api.nova import novaclient
def server_group_list(request, all_projects=False): def server_group_list(request, all_projects=False):
@ -34,8 +35,7 @@ def provider_network_get(request, providernet_id):
class DeviceUsage(base.APIResourceWrapper): class DeviceUsage(base.APIResourceWrapper):
"""Wrapper for Inventory Device Usage """Wrapper for Inventory Device Usage"""
"""
_attrs = ['device_id', 'device_name', 'vendor_id', 'class_id', _attrs = ['device_id', 'device_name', 'vendor_id', 'class_id',
'pci_vfs_configured', 'pci_vfs_used', 'pci_vfs_configured', 'pci_vfs_used',
'pci_pfs_configured', 'pci_pfs_used'] 'pci_pfs_configured', 'pci_pfs_used']
@ -56,8 +56,7 @@ def get_device_usage(request, device_id):
class DetailUsage(base.APIResourceWrapper): class DetailUsage(base.APIResourceWrapper):
"""Wrapper for Inventory Device Usage """Wrapper for Inventory Device Usage"""
"""
_attrs = ['host', _attrs = ['host',
'pci_vfs_configured', 'pci_vfs_used', 'pci_vfs_configured', 'pci_vfs_used',
'pci_pfs_configured', 'pci_pfs_used'] 'pci_pfs_configured', 'pci_pfs_used']

View File

@ -14,10 +14,8 @@
# #
import logging import logging
try:
from urlparse import urlparse from six.moves.urllib.parse import urlparse
except ModuleNotFoundError:
from urllib.parse import urlparse
import requests import requests

View File

@ -26,7 +26,6 @@ from django.conf import settings
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from openstack_dashboard.api import base from openstack_dashboard.api import base
from starlingx_dashboard.api import base as stx_base
import cgcs_patch.constants as patch_constants import cgcs_patch.constants as patch_constants
import sysinv.common.constants as constants import sysinv.common.constants as constants
@ -2005,12 +2004,14 @@ class InterfaceNetwork(base.APIResourceWrapper):
def interface_network_list_by_host(request, host_uuid): def interface_network_list_by_host(request, host_uuid):
interface_networks = cgtsclient(request).interface_network.list_by_host(host_uuid) interface_networks = cgtsclient(request).interface_network.list_by_host(
host_uuid)
return [InterfaceNetwork(n) for n in interface_networks] return [InterfaceNetwork(n) for n in interface_networks]
def interface_network_list_by_interface(request, interface_uuid): def interface_network_list_by_interface(request, interface_uuid):
interface_networks = cgtsclient(request).interface_network.list_by_interface(interface_uuid) interface_networks = cgtsclient(request).interface_network.\
list_by_interface(interface_uuid)
return [InterfaceNetwork(n) for n in interface_networks] return [InterfaceNetwork(n) for n in interface_networks]

View File

@ -10,14 +10,12 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
# #
# Copyright (c) 2016 Wind River Systems, Inc. # Copyright (c) 2016-2018 Wind River Systems, Inc.
# #
import logging import logging
try:
from urlparse import urlparse from six.moves.urllib.parse import urlparse
except ModuleNotFoundError:
from urllib.parse import urlparse
from openstack_dashboard.api import base from openstack_dashboard.api import base

View File

@ -16,7 +16,7 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
# #
# Copyright (c) 2013-2015 Wind River Systems, Inc. # Copyright (c) 2013-2018 Wind River Systems, Inc.
# #
@ -30,7 +30,6 @@ from django.utils.translation import ungettext_lazy
from horizon import exceptions from horizon import exceptions
from horizon import tables from horizon import tables
from horizon.utils import filters as utils_filters from horizon.utils import filters as utils_filters
from openstack_dashboard import api
from starlingx_dashboard import api as stx_api from starlingx_dashboard import api as stx_api
SUPPRESSION_STATUS_CHOICES = ( SUPPRESSION_STATUS_CHOICES = (

View File

@ -16,7 +16,7 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
# #
# Copyright (c) 2013-2015 Wind River Systems, Inc. # Copyright (c) 2013-2018 Wind River Systems, Inc.
# #
@ -24,7 +24,6 @@ from django.utils.translation import ugettext_lazy as _ # noqa
from horizon import exceptions from horizon import exceptions
from horizon import tabs from horizon import tabs
from openstack_dashboard import api
from starlingx_dashboard import api as stx_api from starlingx_dashboard import api as stx_api
from starlingx_dashboard.dashboards.admin.fault_management import tables from starlingx_dashboard.dashboards.admin.fault_management import tables
@ -115,9 +114,6 @@ class ActiveAlarmsTab(tabs.TableTab):
def get_alarms_data(self): def get_alarms_data(self):
search_opts = {} search_opts = {}
# get retrieve parameters from request/session env # get retrieve parameters from request/session env
marker = \
self.request.GET.get(tables.AlarmsTable._meta.pagination_param,
None)
limit = \ limit = \
self.request.GET.get(tables.AlarmsTable._meta.limit_param, self.request.GET.get(tables.AlarmsTable._meta.limit_param,
None) None)

View File

@ -16,7 +16,7 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
# #
# Copyright (c) 2013-2014 Wind River Systems, Inc. # Copyright (c) 2013-2018 Wind River Systems, Inc.
# #
@ -30,8 +30,8 @@ from horizon import exceptions
from horizon import tabs from horizon import tabs
from horizon import views from horizon import views
from openstack_dashboard.api.base import is_service_enabled from openstack_dashboard.api.base import is_service_enabled
from starlingx_dashboard.api import fm
from starlingx_dashboard.api import dc_manager from starlingx_dashboard.api import dc_manager
from starlingx_dashboard.api import fm
from starlingx_dashboard.dashboards.admin.fault_management import \ from starlingx_dashboard.dashboards.admin.fault_management import \
tabs as project_tabs tabs as project_tabs

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2016 Wind River Systems, Inc. # Copyright (c) 2016-2018 Wind River Systems, Inc.
# #
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# #
@ -34,4 +34,5 @@ class HostTopology(horizon.Panel):
else: else:
return True return True
dashboard.Admin.register(HostTopology) dashboard.Admin.register(HostTopology)

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2016 Wind River Systems, Inc. # Copyright (c) 2016-2018 Wind River Systems, Inc.
# #
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# #
@ -12,8 +12,8 @@ from starlingx_dashboard.dashboards.admin.fault_management import \
tables as fm_tables tables as fm_tables
from starlingx_dashboard.dashboards.admin.inventory.interfaces import \ from starlingx_dashboard.dashboards.admin.inventory.interfaces import \
tables as if_tables tables as if_tables
from starlingx_dashboard.dashboards.admin.providernets.providernets.ranges import \ from starlingx_dashboard.dashboards.admin.providernets.providernets.ranges \
tables as sr_tables import tables as sr_tables
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2016 Wind River Systems, Inc. # Copyright (c) 2016-2018 Wind River Systems, Inc.
# #
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# #
@ -159,14 +159,14 @@ class JSONView(View):
tenant_id = self.request.user.tenant_id tenant_id = self.request.user.tenant_id
for resource in resources: for resource in resources:
if (resource.get('tenant_id') and if (resource.get('tenant_id') and
tenant_id != resource.get('tenant_id')): tenant_id != resource.get('tenant_id')):
continue continue
resource['url'] = reverse(view, None, [str(resource['id'])]) resource['url'] = reverse(view, None, [str(resource['id'])])
def _check_router_external_port(self, ports, router_id, network_id): def _check_router_external_port(self, ports, router_id, network_id):
for port in ports: for port in ports:
if (port['network_id'] == network_id and if (port['network_id'] == network_id and
port['device_id'] == router_id): port['device_id'] == router_id):
return True return True
return False return False

View File

@ -76,8 +76,8 @@ class CreateAddress(tables.LinkAction):
return False return False
if interface.ifclass == 'platform': if interface.ifclass == 'platform':
interface_networks = stx_api.sysinv.interface_network_list_by_interface(request, interface_networks = stx_api.sysinv.\
interface.uuid) interface_network_list_by_interface(request, interface.uuid)
for interface_network in interface_networks: for interface_network in interface_networks:
if interface_network.network_type in ALLOWED_INTERFACE_TYPES: if interface_network.network_type in ALLOWED_INTERFACE_TYPES:
return True return True

View File

@ -390,10 +390,6 @@ class AddInterface(forms.SelfHandlingForm):
host_uuid = kwargs['initial']['ihost_uuid'] host_uuid = kwargs['initial']['ihost_uuid']
# Retrieve SDN configuration
sdn_enabled = kwargs['initial']['sdn_enabled']
sdn_l3_mode = kwargs['initial']['sdn_l3_mode_enabled']
# Populate Address Pool selections # Populate Address Pool selections
pools = sysinv.address_pool_list(self.request) pools = sysinv.address_pool_list(self.request)
self.fields['ipv4_pool'].choices = _get_ipv4_pool_choices(pools) self.fields['ipv4_pool'].choices = _get_ipv4_pool_choices(pools)
@ -640,23 +636,19 @@ class UpdateInterface(AddInterface):
ifclass_val = kwargs['initial']['ifclass'] ifclass_val = kwargs['initial']['ifclass']
host_uuid = kwargs['initial']['ihost_uuid'] host_uuid = kwargs['initial']['ihost_uuid']
# Get the SDN configuration
sdn_enabled = kwargs['initial']['sdn_enabled']
sdn_l3_mode = kwargs['initial']['sdn_l3_mode_enabled']
this_interface_id = kwargs['initial']['id'] this_interface_id = kwargs['initial']['id']
iftype_val = kwargs['initial']['iftype'] iftype_val = kwargs['initial']['iftype']
interface_networks = sysinv.interface_network_list_by_interface(self.request, interface_networks = sysinv.interface_network_list_by_interface(
this_interface_id) self.request, this_interface_id)
if ifclass_val == 'platform': if ifclass_val == 'platform':
# Load the networks associated with this interface # Load the networks associated with this interface
network_choices = self.fields['networks'].choices network_choices = self.fields['networks'].choices
network_choice_dict = dict(network_choices) network_choice_dict = dict(network_choices)
initial_networks = [] initial_networks = []
for i in interface_networks: for i in interface_networks:
for uuid, name in network_choice_dict.items(): for uuid in network_choice_dict.keys():
if i.network_uuid == uuid: if i.network_uuid == uuid:
initial_networks.append(uuid) initial_networks.append(uuid)
@ -750,7 +742,8 @@ class UpdateInterface(AddInterface):
ifclass = cleaned_data.get('ifclass') ifclass = cleaned_data.get('ifclass')
interface_id = cleaned_data.get('id') interface_id = cleaned_data.get('id')
networks = cleaned_data.pop('networks', []) networks = cleaned_data.pop('networks', [])
interface_networks = sysinv.interface_network_list_by_interface(self.request, interface_id) interface_networks = sysinv.interface_network_list_by_interface(
self.request, interface_id)
network_ids = [] network_ids = []
networks_to_add = [] networks_to_add = []
networks_to_remove = [] networks_to_remove = []
@ -773,7 +766,8 @@ class UpdateInterface(AddInterface):
interface_networks_to_remove.append(i.uuid) interface_networks_to_remove.append(i.uuid)
cleaned_data['networks'] = network_ids cleaned_data['networks'] = network_ids
cleaned_data['networks_to_add'] = networks_to_add cleaned_data['networks_to_add'] = networks_to_add
cleaned_data['interface_networks_to_remove'] = interface_networks_to_remove cleaned_data['interface_networks_to_remove'] = \
interface_networks_to_remove
return cleaned_data return cleaned_data
def handle(self, request, data): def handle(self, request, data):
@ -855,7 +849,8 @@ class UpdateInterface(AddInterface):
else: else:
del data['networks'] del data['networks']
if data['networks_to_add']: if data['networks_to_add']:
data['networks_to_add'] = str(",".join(data['networks_to_add'])) data['networks_to_add'] = \
str(",".join(data['networks_to_add']))
else: else:
del data['networks_to_add'] del data['networks_to_add']
if data['interface_networks_to_remove']: if data['interface_networks_to_remove']:

View File

@ -1,5 +1,3 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 NEC Corporation # Copyright 2012 NEC Corporation
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may # Licensed under the Apache License, Version 2.0 (the "License"); you may
@ -14,7 +12,7 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
# #
# Copyright (c) 2013-2014 Wind River Systems, Inc. # Copyright (c) 2013-2018 Wind River Systems, Inc.
# #

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2013-2016 Wind River Systems, Inc. # Copyright (c) 2013-2018 Wind River Systems, Inc.
# #
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# #
@ -55,7 +55,8 @@ def get_port_data(request, host_id, interface=None):
# neighbours # neighbours
neighbour_list = \ neighbour_list = \
stx_api.sysinv.host_lldpneighbour_list(request, host_id) stx_api.sysinv.host_lldpneighbour_list(request, host_id)
interface_list = stx_api.sysinv.host_interface_list(request, host_id) interface_list = stx_api.sysinv.host_interface_list(request,
host_id)
for p in port_list: for p in port_list:
port_info = "%s (%s, %s, " % (p.get_port_display_name(), port_info = "%s (%s, %s, " % (p.get_port_display_name(),
@ -184,13 +185,14 @@ class AddInterfaceProfileView(forms.ModalFormView):
try: try:
host = stx_api.sysinv.host_get(self.request, host_id) host = stx_api.sysinv.host_get(self.request, host_id)
all_ports = stx_api.sysinv.host_port_list(self.request, host.uuid) all_ports = stx_api.sysinv.host_port_list(self.request,
host.uuid)
host.ports = [p for p in all_ports if p.interface_uuid] host.ports = [p for p in all_ports if p.interface_uuid]
for p in host.ports: for p in host.ports:
p.namedisplay = p.get_port_display_name() p.namedisplay = p.get_port_display_name()
host.interfaces = stx_api.sysinv.host_interface_list(self.request, host.interfaces = stx_api.sysinv.host_interface_list(
host.uuid) self.request, host.uuid)
for i in host.interfaces: for i in host.interfaces:
i.ports = [p.get_port_display_name() i.ports = [p.get_port_display_name()
for p in all_ports if for p in all_ports if

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2013-2014 Wind River Systems, Inc. # Copyright (c) 2013-2018 Wind River Systems, Inc.
# #
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# #
@ -339,7 +339,8 @@ class AddMemoryProfile(forms.SelfHandlingForm):
memoryProfileName = data['profilename'] memoryProfileName = data['profilename']
try: try:
memoryProfile = stx_api.sysinv.host_memprofile_create(request, **data) memoryProfile = stx_api.sysinv.host_memprofile_create(
request, **data)
msg = _('Memory Profile "%s" was successfully created.') % \ msg = _('Memory Profile "%s" was successfully created.') % \
memoryProfileName memoryProfileName
LOG.debug(msg) LOG.debug(msg)

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2013-2014 Wind River Systems, Inc. # Copyright (c) 2013-2018 Wind River Systems, Inc.
# #
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# #
@ -85,13 +85,15 @@ class AddMemoryProfileView(forms.ModalFormView):
host_id = self.kwargs['host_id'] host_id = self.kwargs['host_id']
try: try:
host = stx_api.sysinv.host_get(self.request, host_id) host = stx_api.sysinv.host_get(self.request, host_id)
host.nodes = stx_api.sysinv.host_node_list(self.request, host.uuid) host.nodes = stx_api.sysinv.host_node_list(self.request,
host.uuid)
host.memory = \ host.memory = \
stx_api.sysinv.host_memory_list(self.request, host.uuid) stx_api.sysinv.host_memory_list(self.request, host.uuid)
numa_node_tuple_list = [] numa_node_tuple_list = []
for m in host.memory: for m in host.memory:
node = stx_api.sysinv.host_node_get(self.request, m.inode_uuid) node = stx_api.sysinv.host_node_get(self.request,
m.inode_uuid)
numa_node_tuple_list.append((node.numa_node, m)) numa_node_tuple_list.append((node.numa_node, m))
host.numa_nodes = numa_node_tuple_list host.numa_nodes = numa_node_tuple_list

View File

@ -1,5 +1,3 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 NEC Corporation # Copyright 2012 NEC Corporation
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may # Licensed under the Apache License, Version 2.0 (the "License"); you may
@ -14,7 +12,7 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
# #
# Copyright (c) 2013-2014 Wind River Systems, Inc. # Copyright (c) 2013-2018 Wind River Systems, Inc.
# #

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2013-2014 Wind River Systems, Inc. # Copyright (c) 2013-2018 Wind River Systems, Inc.
# #
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# #
@ -39,7 +39,8 @@ class UpdateView(forms.ModalFormView):
port_id = self.kwargs['port_id'] port_id = self.kwargs['port_id']
host_id = self.kwargs['host_id'] host_id = self.kwargs['host_id']
try: try:
self._object = stx_api.sysinv.host_port_get(self.request, port_id) self._object = stx_api.sysinv.host_port_get(self.request,
port_id)
self._object.host_id = host_id self._object.host_id = host_id
except Exception: except Exception:
redirect = reverse("horizon:project:networks:detail", redirect = reverse("horizon:project:networks:detail",

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2013-2015 Wind River Systems, Inc. # Copyright (c) 2013-2018 Wind River Systems, Inc.
# #
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# #
@ -75,7 +75,8 @@ class AddSensorGroup(forms.SelfHandlingForm):
del data['hostname'] del data['hostname']
# The REST API takes care of creating the sensorgroup and assoc # The REST API takes care of creating the sensorgroup and assoc
sensorgroup = stx_api.sysinv.host_sensorgroup_create(request, **data) sensorgroup = stx_api.sysinv.host_sensorgroup_create(request,
**data)
msg = _('Sensor group was successfully created.') msg = _('Sensor group was successfully created.')
LOG.debug(msg) LOG.debug(msg)
@ -208,9 +209,10 @@ class UpdateSensorGroup(forms.SelfHandlingForm):
mysensorgroupname = data.pop('sensorgroupname', None) mysensorgroupname = data.pop('sensorgroupname', None)
try: try:
sensorgroup = stx_api.sysinv.host_sensorgroup_update(request, sensorgroup = \
sensorgroup_id, stx_api.sysinv.host_sensorgroup_update(request,
**data) sensorgroup_id,
**data)
msg = _('SensorGroup "%s" was ' msg = _('SensorGroup "%s" was '
'successfully updated.') % mysensorgroupname 'successfully updated.') % mysensorgroupname

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2013-2015 Wind River Systems, Inc. # Copyright (c) 2013-2018 Wind River Systems, Inc.
# #
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# #
@ -209,7 +209,8 @@ class RelearnSensorModel(tables.Action):
def single(self, table, request, obj_ids): def single(self, table, request, obj_ids):
LOG.debug("requesting relearn of sensor model for host " LOG.debug("requesting relearn of sensor model for host "
"%s", table.kwargs['host'].uuid) "%s", table.kwargs['host'].uuid)
stx_api.sysinv.host_sensorgroup_relearn(request, table.kwargs['host'].uuid) stx_api.sysinv.host_sensorgroup_relearn(request,
table.kwargs['host'].uuid)
class SensorGroupsTable(tables.DataTable): class SensorGroupsTable(tables.DataTable):

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2013-2015 Wind River Systems, Inc. # Copyright (c) 2013-2018 Wind River Systems, Inc.
# #
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# #
@ -74,8 +74,9 @@ class UpdateSensorGroupView(forms.ModalFormView):
LOG.debug("sensorgroup_id=%s kwargs=%s", LOG.debug("sensorgroup_id=%s kwargs=%s",
sensorgroup_id, self.kwargs) sensorgroup_id, self.kwargs)
try: try:
self._object = stx_api.sysinv.host_sensorgroup_get(self.request, self._object = \
sensorgroup_id) stx_api.sysinv.host_sensorgroup_get(self.request,
sensorgroup_id)
self._object.host_id = host_id self._object.host_id = host_id
except Exception: except Exception:
@ -147,7 +148,8 @@ class DetailSensorView(views.HorizonTemplateView):
if not hasattr(self, "_sensor"): if not hasattr(self, "_sensor"):
sensor_id = self.kwargs['sensor_id'] sensor_id = self.kwargs['sensor_id']
try: try:
sensor = stx_api.sysinv.host_sensor_get(self.request, sensor_id) sensor = stx_api.sysinv.host_sensor_get(self.request,
sensor_id)
except Exception: except Exception:
redirect = reverse('horizon:admin:inventory:index') redirect = reverse('horizon:admin:inventory:index')
exceptions.handle(self.request, exceptions.handle(self.request,
@ -194,8 +196,9 @@ class DetailSensorGroupView(views.HorizonTemplateView):
if not hasattr(self, "_sensorgroup"): if not hasattr(self, "_sensorgroup"):
sensorgroup_id = self.kwargs['sensorgroup_id'] sensorgroup_id = self.kwargs['sensorgroup_id']
try: try:
sensorgroup = stx_api.sysinv.host_sensorgroup_get(self.request, sensorgroup = \
sensorgroup_id) stx_api.sysinv.host_sensorgroup_get(self.request,
sensorgroup_id)
except Exception: except Exception:
redirect = reverse('horizon:admin:inventory:index') redirect = reverse('horizon:admin:inventory:index')
exceptions.handle(self.request, exceptions.handle(self.request,

View File

@ -40,7 +40,8 @@ class AddDiskProfile(forms.SelfHandlingForm):
def handle(self, request, data): def handle(self, request, data):
diskProfileName = data['profilename'] diskProfileName = data['profilename']
try: try:
diskProfile = stx_api.sysinv.host_diskprofile_create(request, **data) diskProfile = stx_api.sysinv.host_diskprofile_create(request,
**data)
msg = _('Storage Profile "%s" was successfully created.') \ msg = _('Storage Profile "%s" was successfully created.') \
% diskProfileName % diskProfileName
@ -72,13 +73,12 @@ class EditStorageVolume(forms.SelfHandlingForm):
help_text=_("Assign disk to journal " help_text=_("Assign disk to journal "
"storage volume.")) "storage volume."))
journal_size_gib = forms.CharField(label=_("Journal Size GiB"), journal_size_gib = forms.CharField(
required=False, label=_("Journal Size GiB"),
initial=stx_api.sysinv.JOURNAL_DEFAULT_SIZE, required=False,
widget=forms.TextInput(attrs={ initial=stx_api.sysinv.JOURNAL_DEFAULT_SIZE,
'data-slug': 'journal_size_gib'}), widget=forms.TextInput(attrs={'data-slug': 'journal_size_gib'}),
help_text=_("Journal's size for the " help_text=_("Journal's size for the current OSD."))
"current OSD."))
failure_url = 'horizon:admin:inventory:detail' failure_url = 'horizon:admin:inventory:detail'
@ -127,7 +127,8 @@ class EditStorageVolume(forms.SelfHandlingForm):
data['journal_location'] = journal data['journal_location'] = journal
else: else:
data['journal_location'] = None data['journal_location'] = None
data['journal_size_mib'] = stx_api.sysinv.JOURNAL_DEFAULT_SIZE * 1024 data['journal_size_mib'] = \
stx_api.sysinv.JOURNAL_DEFAULT_SIZE * 1024
del data['journal_locations'] del data['journal_locations']
del data['id'] del data['id']
@ -216,16 +217,15 @@ class AddStorageVolume(forms.SelfHandlingForm):
"journal storage " "journal storage "
"volume.")) "volume."))
journal_size_gib = forms.CharField(label=_("Journal Size GiB"), journal_size_gib = forms.CharField(
required=False, label=_("Journal Size GiB"),
initial=stx_api.sysinv.JOURNAL_DEFAULT_SIZE, required=False,
widget=forms.TextInput(attrs={ initial=stx_api.sysinv.JOURNAL_DEFAULT_SIZE,
'class': 'switched', widget=forms.TextInput(attrs={
'data-switch-on': 'function', 'class': 'switched',
'data-function-osd': 'data-switch-on': 'function',
_("Journal Size GiB")}), 'data-function-osd': _("Journal Size GiB")}),
help_text=_("Journal's size for the" help_text=_("Journal's size for the current OSD."))
"current OSD."))
tiers = forms.ChoiceField(label=_("Storage Tier"), tiers = forms.ChoiceField(label=_("Storage Tier"),
required=False, required=False,
@ -245,7 +245,8 @@ class AddStorageVolume(forms.SelfHandlingForm):
this_stor_uuid = 0 this_stor_uuid = 0
host_uuid = kwargs['initial']['ihost_uuid'] host_uuid = kwargs['initial']['ihost_uuid']
avail_disk_list = stx_api.sysinv.host_disk_list(self.request, host_uuid) avail_disk_list = stx_api.sysinv.host_disk_list(self.request,
host_uuid)
disk_tuple_list = [] disk_tuple_list = []
for d in avail_disk_list: for d in avail_disk_list:
if d.istor_uuid and d.istor_uuid != this_stor_uuid: if d.istor_uuid and d.istor_uuid != this_stor_uuid:
@ -321,7 +322,8 @@ class AddStorageVolume(forms.SelfHandlingForm):
data['journal_location'] = journal data['journal_location'] = journal
else: else:
data['journal_location'] = None data['journal_location'] = None
data['journal_size_mib'] = stx_api.sysinv.JOURNAL_DEFAULT_SIZE * 1024 data['journal_size_mib'] = \
stx_api.sysinv.JOURNAL_DEFAULT_SIZE * 1024
try: try:
del data['host_id'] del data['host_id']
@ -543,7 +545,8 @@ class AddPhysicalVolume(forms.SelfHandlingForm):
if stx_api.sysinv.SUBFUNCTIONS_COMPUTE in subfunctions: if stx_api.sysinv.SUBFUNCTIONS_COMPUTE in subfunctions:
compatible_lvgs += [stx_api.sysinv.LVG_NOVA_LOCAL] compatible_lvgs += [stx_api.sysinv.LVG_NOVA_LOCAL]
avail_disk_list = stx_api.sysinv.host_disk_list(self.request, host_uuid) avail_disk_list = stx_api.sysinv.host_disk_list(self.request,
host_uuid)
ilvg_list = stx_api.sysinv.host_lvg_list(self.request, host_uuid) ilvg_list = stx_api.sysinv.host_lvg_list(self.request, host_uuid)
partitions = stx_api.sysinv.host_disk_partition_list(self.request, partitions = stx_api.sysinv.host_disk_partition_list(self.request,
host_uuid) host_uuid)
@ -558,7 +561,8 @@ class AddPhysicalVolume(forms.SelfHandlingForm):
for lvg in ilvg_list: for lvg in ilvg_list:
if (lvg.lvm_vg_name in compatible_lvgs and if (lvg.lvm_vg_name in compatible_lvgs and
lvg.vg_state in [stx_api.sysinv.LVG_ADD, stx_api.sysinv.LVG_PROV]): lvg.vg_state in [stx_api.sysinv.LVG_ADD,
stx_api.sysinv.LVG_PROV]):
if (lvg.lvm_vg_name == stx_api.sysinv.LVG_CINDER_VOLUMES and if (lvg.lvm_vg_name == stx_api.sysinv.LVG_CINDER_VOLUMES and
pv_cinder_volumes): pv_cinder_volumes):
continue continue
@ -777,7 +781,8 @@ class CreatePartition(forms.SelfHandlingForm):
# Populate disk choices. # Populate disk choices.
host_uuid = kwargs['initial']['ihost_uuid'] host_uuid = kwargs['initial']['ihost_uuid']
avail_disk_list = stx_api.sysinv.host_disk_list(self.request, host_uuid) avail_disk_list = stx_api.sysinv.host_disk_list(self.request,
host_uuid)
disk_tuple_list = [] disk_tuple_list = []
for d in avail_disk_list: for d in avail_disk_list:
disk_model = d.get_model_num() disk_model = d.get_model_num()
@ -812,7 +817,8 @@ class CreatePartition(forms.SelfHandlingForm):
del data['size_gib'] del data['size_gib']
data['type_guid'] = stx_api.sysinv.USER_PARTITION_PHYS_VOL data['type_guid'] = stx_api.sysinv.USER_PARTITION_PHYS_VOL
# The REST API takes care of creating the partition. # The REST API takes care of creating the partition.
partition = stx_api.sysinv.host_disk_partition_create(request, **data) partition = stx_api.sysinv.host_disk_partition_create(request,
**data)
msg = _('Partition was successfully created.') msg = _('Partition was successfully created.')
LOG.debug(msg) LOG.debug(msg)

View File

@ -1,6 +1,4 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4 # Copyright (c) 2015-2018 Wind River Systems, Inc.
# Copyright (c) 2015-2017 Wind River Systems, Inc.
# #
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# #

View File

@ -1,6 +1,4 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4 # Copyright (c) 2015-2018 Wind River Systems, Inc.
# Copyright (c) 2015 Wind River Systems, Inc.
# #
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# #

View File

@ -1,6 +1,4 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4 # Copyright (c) 2015-2018 Wind River Systems, Inc.
# Copyright (c) 2015 Wind River Systems, Inc.
# #
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# #

View File

@ -1,6 +1,4 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4 # Copyright (c) 2015-2018 Wind River Systems, Inc.
# Copyright (c) 2015 Wind River Systems, Inc.
# #
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# #

View File

@ -1,6 +1,4 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4 # Copyright (c) 2015-2018 Wind River Systems, Inc.
# Copyright (c) 2015 Wind River Systems, Inc.
# #
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# #

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2013-2017 Wind River Systems, Inc. # Copyright (c) 2013-2018 Wind River Systems, Inc.
# #
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# #
@ -720,13 +720,16 @@ class Hosts(tables.DataTable):
display_choices=stx_api.sysinv.Host.PERSONALITY_DISPLAY_CHOICES) display_choices=stx_api.sysinv.Host.PERSONALITY_DISPLAY_CHOICES)
admin = tables.Column("administrative", admin = tables.Column("administrative",
verbose_name=_("Admin State"), verbose_name=_("Admin State"),
display_choices=stx_api.sysinv.Host.ADMIN_DISPLAY_CHOICES) display_choices=stx_api.sysinv.
Host.ADMIN_DISPLAY_CHOICES)
oper = tables.Column("operational", oper = tables.Column("operational",
verbose_name=_("Operational State"), verbose_name=_("Operational State"),
display_choices=stx_api.sysinv.Host.OPER_DISPLAY_CHOICES) display_choices=stx_api.sysinv.
Host.OPER_DISPLAY_CHOICES)
avail = tables.Column("availability", avail = tables.Column("availability",
verbose_name=_("Availability State"), verbose_name=_("Availability State"),
display_choices=stx_api.sysinv.Host.AVAIL_DISPLAY_CHOICES) display_choices=stx_api.sysinv.
Host.AVAIL_DISPLAY_CHOICES)
uptime = tables.Column('boottime', uptime = tables.Column('boottime',
verbose_name=_('Uptime'), verbose_name=_('Uptime'),
filters=(timesince,), filters=(timesince,),

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2013-2017 Wind River Systems, Inc. # Copyright (c) 2013-2018 Wind River Systems, Inc.
# #
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# #
@ -101,7 +101,8 @@ class HostsTab(tabs.TableTab):
return hosts return hosts
def get_hostscontroller_data(self): def get_hostscontroller_data(self):
controllers = self.get_hosts_data(stx_api.sysinv.PERSONALITY_CONTROLLER) controllers = self.get_hosts_data(
stx_api.sysinv.PERSONALITY_CONTROLLER)
return controllers return controllers
@ -543,10 +544,12 @@ class InterfacesTab(tabs.TableTab):
platform_network_names = [] platform_network_names = []
if i.ifclass == 'platform': if i.ifclass == 'platform':
for interface_network in stx_api.sysinv.interface_network_list_by_interface(self.request, for interface_network in stx_api.sysinv.\
i.uuid): interface_network_list_by_interface(
self.request, i.uuid):
if str(interface_network.network_id) in i.networks: if str(interface_network.network_id) in i.networks:
platform_network_names.append(interface_network.network_name) platform_network_names.append(
interface_network.network_name)
i.platform_network_names = platform_network_names i.platform_network_names = platform_network_names
if i.iftype == 'ethernet': if i.iftype == 'ethernet':

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2013-2017 Wind River Systems, Inc. # Copyright (c) 2013-2018 Wind River Systems, Inc.
# #
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# #
@ -27,6 +27,8 @@ from starlingx_dashboard.dashboards.admin.inventory.ports import \
views as port_views views as port_views
from starlingx_dashboard.dashboards.admin.inventory.sensors import \ from starlingx_dashboard.dashboards.admin.inventory.sensors import \
views as sensor_views views as sensor_views
from starlingx_dashboard.dashboards.admin.inventory.storages import \
urls as storages_urls
from starlingx_dashboard.dashboards.admin.inventory.storages import \ from starlingx_dashboard.dashboards.admin.inventory.storages import \
views as storage_views views as storage_views
from starlingx_dashboard.dashboards.admin.inventory.views import \ from starlingx_dashboard.dashboards.admin.inventory.views import \
@ -37,8 +39,6 @@ from starlingx_dashboard.dashboards.admin.inventory.views import \
IndexView IndexView
from starlingx_dashboard.dashboards.admin.inventory.views import \ from starlingx_dashboard.dashboards.admin.inventory.views import \
UpdateView UpdateView
from starlingx_dashboard.dashboards.admin.inventory.storages \
import urls as storages_urls
urlpatterns = [ urlpatterns = [

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2013-2017 Wind River Systems, Inc. # Copyright (c) 2013-2018 Wind River Systems, Inc.
# #
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# #
@ -64,7 +64,8 @@ class UpdateView(workflows.WorkflowView):
def get_initial(self): def get_initial(self):
try: try:
host = stx_api.sysinv.host_get(self.request, self.kwargs['host_id']) host = stx_api.sysinv.host_get(self.request,
self.kwargs['host_id'])
except Exception: except Exception:
exceptions.handle(self.request, exceptions.handle(self.request,
_("Unable to retrieve host data.")) _("Unable to retrieve host data."))
@ -109,8 +110,10 @@ class DetailView(tabs.TabbedTableView):
try: try:
host = stx_api.sysinv.host_get(self.request, host_id) host = stx_api.sysinv.host_get(self.request, host_id)
host.nodes = stx_api.sysinv.host_node_list(self.request, host.uuid) host.nodes = stx_api.sysinv.host_node_list(self.request,
host.cpus = stx_api.sysinv.host_cpu_list(self.request, host.uuid) host.uuid)
host.cpus = stx_api.sysinv.host_cpu_list(self.request,
host.uuid)
icpu_utils.restructure_host_cpu_data(host) icpu_utils.restructure_host_cpu_data(host)
host.memorys = stx_api.sysinv.host_memory_list(self.request, host.memorys = stx_api.sysinv.host_memory_list(self.request,
@ -121,13 +124,16 @@ class DetailView(tabs.TabbedTableView):
m.numa_node = n.numa_node m.numa_node = n.numa_node
break break
host.ports = stx_api.sysinv.host_port_list(self.request, host.uuid) host.ports = stx_api.sysinv.host_port_list(self.request,
host.interfaces = stx_api.sysinv.host_interface_list(self.request, host.uuid)
host.uuid) host.interfaces = stx_api.sysinv.host_interface_list(
self.request, host.uuid)
host.devices = stx_api.sysinv.host_device_list(self.request, host.devices = stx_api.sysinv.host_device_list(self.request,
host.uuid) host.uuid)
host.disks = stx_api.sysinv.host_disk_list(self.request, host.uuid) host.disks = stx_api.sysinv.host_disk_list(self.request,
host.stors = stx_api.sysinv.host_stor_list(self.request, host.uuid) host.uuid)
host.stors = stx_api.sysinv.host_stor_list(self.request,
host.uuid)
host.pvs = stx_api.sysinv.host_pv_list(self.request, host.uuid) host.pvs = stx_api.sysinv.host_pv_list(self.request, host.uuid)
host.partitions = stx_api.sysinv.host_disk_partition_list( host.partitions = stx_api.sysinv.host_disk_partition_list(
self.request, host.uuid) self.request, host.uuid)
@ -137,7 +143,8 @@ class DetailView(tabs.TabbedTableView):
p.status = stx_api.sysinv.PARTITION_STATUS_MSG[p.status] p.status = stx_api.sysinv.PARTITION_STATUS_MSG[p.status]
host.lldpneighbours = \ host.lldpneighbours = \
stx_api.sysinv.host_lldpneighbour_list(self.request, host.uuid) stx_api.sysinv.host_lldpneighbour_list(self.request,
host.uuid)
# Set the value for neighbours field for each port in the host. # Set the value for neighbours field for each port in the host.
# This will be referenced in Interfaces table # This will be referenced in Interfaces table
@ -151,7 +158,8 @@ class DetailView(tabs.TabbedTableView):
pv.pv_state = self._adjust_state_data(pv.pv_state, pv.pv_state = self._adjust_state_data(pv.pv_state,
pv.lvm_vg_name) pv.lvm_vg_name)
host.lvgs = stx_api.sysinv.host_lvg_list(self.request, host.uuid, host.lvgs = stx_api.sysinv.host_lvg_list(self.request,
host.uuid,
get_params=True) get_params=True)
# Adjust lvg state to be more "user friendly" # Adjust lvg state to be more "user friendly"

View File

@ -56,8 +56,8 @@ BM_TYPES_CHOICES = (
def ifprofile_applicable(request, host, profile): def ifprofile_applicable(request, host, profile):
for interface in profile.interfaces: for interface in profile.interfaces:
interface_networks = stx_api.sysinv.interface_network_list_by_interface(request, interface_networks = stx_api.sysinv.\
interface.uuid) interface_network_list_by_interface(request, interface.uuid)
if (stx_api.sysinv.PERSONALITY_COMPUTE == host._personality and if (stx_api.sysinv.PERSONALITY_COMPUTE == host._personality and
any(interface_network.network_type == 'oam' any(interface_network.network_type == 'oam'
for interface_network in interface_networks)): for interface_network in interface_networks)):
@ -248,8 +248,8 @@ class UpdateHostInfoAction(workflows.Action):
attrs={'class': 'switched', attrs={'class': 'switched',
'data-switch-on': 'personality', 'data-switch-on': 'personality',
'data-personality-' + 'data-personality-' +
stx_api.sysinv.PERSONALITY_COMPUTE: _( stx_api.sysinv.PERSONALITY_COMPUTE:
"Host Name")})) _("Host Name")}))
location = forms.CharField(label=_("Location"), location = forms.CharField(label=_("Location"),
initial='location', initial='location',
@ -345,8 +345,8 @@ class UpdateHostInfoAction(workflows.Action):
if host.nodes and host.cpus and host.ports: if host.nodes and host.cpus and host.ports:
# Populate Available Cpu Profile Choices # Populate Available Cpu Profile Choices
try: try:
avail_cpu_profile_list = stx_api.sysinv.host_cpuprofile_list( avail_cpu_profile_list = \
self.request) stx_api.sysinv.host_cpuprofile_list(self.request)
host_profile = icpu_utils.HostCpuProfile( host_profile = icpu_utils.HostCpuProfile(
host.subfunctions, host.subfunctions,
@ -393,8 +393,8 @@ class UpdateHostInfoAction(workflows.Action):
self.fields[ self.fields[
'interfaceProfile'].widget = forms.widgets.HiddenInput() 'interfaceProfile'].widget = forms.widgets.HiddenInput()
if ((personality == 'storage' or 'compute' in host._subfunctions) and if ((personality == 'storage' or
host.disks): 'compute' in host._subfunctions) and host.disks):
# Populate Available Disk Profile Choices # Populate Available Disk Profile Choices
try: try:
disk_profile_tuple_list = [ disk_profile_tuple_list = [
@ -467,10 +467,11 @@ class UpdateHostInfoAction(workflows.Action):
if cleaned_data['personality'] == stx_api.sysinv.PERSONALITY_STORAGE: if cleaned_data['personality'] == stx_api.sysinv.PERSONALITY_STORAGE:
self._subfunctions = stx_api.sysinv.PERSONALITY_STORAGE self._subfunctions = stx_api.sysinv.PERSONALITY_STORAGE
cleaned_data['subfunctions'] = self._subfunctions cleaned_data['subfunctions'] = self._subfunctions
elif cleaned_data['personality'] == stx_api.sysinv.PERSONALITY_CONTROLLER: elif cleaned_data['personality'] == \
stx_api.sysinv.PERSONALITY_CONTROLLER:
if self.system_type == constants.TS_AIO: if self.system_type == constants.TS_AIO:
self._subfunctions = (stx_api.sysinv.PERSONALITY_CONTROLLER + ',' + self._subfunctions = (stx_api.sysinv.PERSONALITY_CONTROLLER +
stx_api.sysinv.PERSONALITY_COMPUTE) ',' + stx_api.sysinv.PERSONALITY_COMPUTE)
else: else:
self._subfunctions = stx_api.sysinv.PERSONALITY_CONTROLLER self._subfunctions = stx_api.sysinv.PERSONALITY_CONTROLLER
cleaned_data['subfunctions'] = self._subfunctions cleaned_data['subfunctions'] = self._subfunctions
@ -629,7 +630,8 @@ class BoardManagementAction(workflows.Action):
'class': 'switched', 'class': 'switched',
'data-switch-on': 'bm_type', 'data-switch-on': 'bm_type',
'data-bm_type-' + 'data-bm_type-' +
stx_api.sysinv.BM_TYPE_GENERIC: FIELD_LABEL_BM_CONFIRM_PASSWORD}), stx_api.sysinv.BM_TYPE_GENERIC:
FIELD_LABEL_BM_CONFIRM_PASSWORD}),
required=False) required=False)
def clean(self): def clean(self):
@ -639,8 +641,6 @@ class BoardManagementAction(workflows.Action):
if 'bm_ip' not in cleaned_data or not cleaned_data['bm_ip']: if 'bm_ip' not in cleaned_data or not cleaned_data['bm_ip']:
raise forms.ValidationError( raise forms.ValidationError(
_('Board management IP address is required.')) _('Board management IP address is required.'))
raise forms.ValidationError(
_('Board management MAC address is required.'))
if 'bm_username' not in cleaned_data or not \ if 'bm_username' not in cleaned_data or not \
cleaned_data['bm_username']: cleaned_data['bm_username']:

View File

@ -12,7 +12,7 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
# #
# Copyright (c) 2013-2014 Wind River Systems, Inc. # Copyright (c) 2013-2018 Wind River Systems, Inc.
# #
@ -89,7 +89,8 @@ class CreateProviderNetwork(forms.SelfHandlingForm):
'mtu': data['mtu'], 'mtu': data['mtu'],
'vlan_transparent': data['vlan_transparent']} 'vlan_transparent': data['vlan_transparent']}
network = stx_api.neutron.provider_network_create(request, **params) network = stx_api.neutron.provider_network_create(request,
**params)
msg = (_('Provider network %s was successfully created.') % msg = (_('Provider network %s was successfully created.') %
data['name']) data['name'])
LOG.debug(msg) LOG.debug(msg)
@ -97,7 +98,7 @@ class CreateProviderNetwork(forms.SelfHandlingForm):
return network return network
except neutron_exceptions.NeutronClientException as e: except neutron_exceptions.NeutronClientException as e:
redirect = reverse('horizon:admin:providernets:index') redirect = reverse('horizon:admin:providernets:index')
exceptions.handle(request, e.message, redirect=redirect) exceptions.handle(request, str(e), redirect=redirect)
except Exception: except Exception:
redirect = reverse('horizon:admin:providernets:index') redirect = reverse('horizon:admin:providernets:index')
msg = _('Failed to create provider network %s') % data['name'] msg = _('Failed to create provider network %s') % data['name']
@ -148,7 +149,7 @@ class UpdateProviderNetwork(forms.SelfHandlingForm):
msg = _('Failed to update provider network %s') % data['name'] msg = _('Failed to update provider network %s') % data['name']
LOG.info(msg) LOG.info(msg)
redirect = reverse(self.failure_url) redirect = reverse(self.failure_url)
exceptions.handle(request, e.message, redirect=redirect) exceptions.handle(request, str(e), redirect=redirect)
except Exception: except Exception:
msg = _('Failed to update provider network %s') % data['name'] msg = _('Failed to update provider network %s') % data['name']
LOG.info(msg) LOG.info(msg)

View File

@ -12,7 +12,7 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
# #
# Copyright (c) 2013-2015,2017 Wind River Systems, Inc. # Copyright (c) 2013-2018 Wind River Systems, Inc.
# #
@ -145,11 +145,11 @@ class CreateProviderNetworkRange(forms.SelfHandlingForm):
messages.success(request, msg) messages.success(request, msg)
return providernet_range return providernet_range
except neutron_exceptions.NeutronClientException as e: except neutron_exceptions.NeutronClientException as e:
LOG.info(e.message) LOG.info(str(e))
redirect = reverse('horizon:admin:providernets:providernets:' redirect = reverse('horizon:admin:providernets:providernets:'
'detail', 'detail',
args=(data['providernet_id'],)) args=(data['providernet_id'],))
exceptions.handle(request, e.message, redirect=redirect) exceptions.handle(request, str(e), redirect=redirect)
except Exception: except Exception:
msg = _('Failed to create a provider' msg = _('Failed to create a provider'
' network range for network %s') \ ' network range for network %s') \
@ -236,11 +236,11 @@ class UpdateProviderNetworkRange(forms.SelfHandlingForm):
messages.success(request, msg) messages.success(request, msg)
return providernet_range return providernet_range
except neutron_exceptions.NeutronClientException as e: except neutron_exceptions.NeutronClientException as e:
LOG.info(e.message) LOG.info(str(e))
redirect = reverse('horizon:admin:providernets:providernets:' redirect = reverse('horizon:admin:providernets:providernets:'
'detail', 'detail',
args=(data['providernet_id'],)) args=(data['providernet_id'],))
exceptions.handle(request, e.message, redirect=redirect) exceptions.handle(request, str(e), redirect=redirect)
except Exception: except Exception:
msg = (_('Failed to update provider network range %s') % msg = (_('Failed to update provider network range %s') %
data['providernet_range_id']) data['providernet_range_id'])

View File

@ -1,5 +1,3 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 NEC Corporation # Copyright 2012 NEC Corporation
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may # Licensed under the Apache License, Version 2.0 (the "License"); you may
@ -14,7 +12,7 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
# #
# Copyright (c) 2013-2014,2017 Wind River Systems, Inc. # Copyright (c) 2013-2018 Wind River Systems, Inc.
# #
@ -61,8 +59,9 @@ class DeleteProviderNetworkRange(tables.DeleteAction):
try: try:
stx_api.neutron.provider_network_range_delete(request, obj_id) stx_api.neutron.provider_network_range_delete(request, obj_id)
except neutron_exceptions.NeutronClientException as e: except neutron_exceptions.NeutronClientException as e:
LOG.info(e.message) LOG.info(str(e))
exceptions.handle(request, e.message, exceptions.handle(request,
str(e),
redirect=self.get_redirect_url()) redirect=self.get_redirect_url())
except Exception: except Exception:
msg = _('Failed to delete provider network range %s') % obj_id msg = _('Failed to delete provider network range %s') % obj_id

View File

@ -1,5 +1,3 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 NEC Corporation # Copyright 2012 NEC Corporation
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may # Licensed under the Apache License, Version 2.0 (the "License"); you may
@ -14,7 +12,7 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
# #
# Copyright (c) 2013-2016 Wind River Systems, Inc. # Copyright (c) 2013-2018 Wind River Systems, Inc.
# #
from django.utils.translation import ugettext_lazy as _ # noqa from django.utils.translation import ugettext_lazy as _ # noqa

View File

@ -1,5 +1,3 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 NEC Corporation # Copyright 2012 NEC Corporation
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may # Licensed under the Apache License, Version 2.0 (the "License"); you may
@ -14,7 +12,7 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
# #
# Copyright (c) 2013-2015 Wind River Systems, Inc. # Copyright (c) 2013-2018 Wind River Systems, Inc.
# #

View File

@ -1,5 +1,3 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 NEC Corporation # Copyright 2012 NEC Corporation
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may # Licensed under the Apache License, Version 2.0 (the "License"); you may
@ -14,7 +12,7 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
# #
# Copyright (c) 2013-2017 Wind River Systems, Inc. # Copyright (c) 2013-2018 Wind River Systems, Inc.
# #
@ -51,8 +49,8 @@ class CreateView(forms.ModalFormView):
if not hasattr(self, "_object"): if not hasattr(self, "_object"):
try: try:
providernet_id = self.kwargs["providernet_id"] providernet_id = self.kwargs["providernet_id"]
self._object = stx_api.neutron.provider_network_get(self.request, self._object = stx_api.neutron.provider_network_get(
providernet_id) self.request, providernet_id)
except Exception: except Exception:
redirect = reverse(self.failure_url, redirect = reverse(self.failure_url,
args=(self.kwargs['providernet_id'],)) args=(self.kwargs['providernet_id'],))

View File

@ -12,7 +12,7 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
# #
# Copyright (c) 2013-2014 Wind River Systems, Inc. # Copyright (c) 2013-2018 Wind River Systems, Inc.
# #
@ -54,9 +54,9 @@ class DeleteProviderNetwork(tables.DeleteAction):
try: try:
stx_api.neutron.provider_network_delete(request, obj_id) stx_api.neutron.provider_network_delete(request, obj_id)
except neutron_exceptions.NeutronClientException as e: except neutron_exceptions.NeutronClientException as e:
LOG.info(e.message) LOG.info(str(e))
redirect = reverse('horizon:admin:providernets:index') redirect = reverse('horizon:admin:providernets:index')
exceptions.handle(request, e.message, redirect=redirect) exceptions.handle(request, str(e), redirect=redirect)
except Exception: except Exception:
msg = _('Failed to delete provider network %s') % obj_id msg = _('Failed to delete provider network %s') % obj_id
LOG.info(msg) LOG.info(msg)

View File

@ -1,196 +1,195 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may # 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 # not use this file except in compliance with the License. You may obtain
# a copy of the License at # a copy of the License at
# #
# http://www.apache.org/licenses/LICENSE-2.0 # http://www.apache.org/licenses/LICENSE-2.0
# #
# Unless required by applicable law or agreed to in writing, software # Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
# #
# Copyright (c) 2013-2017 Wind River Systems, Inc. # Copyright (c) 2013-2018 Wind River Systems, Inc.
# #
# Copyright 2012 Nebula, Inc. # Copyright 2012 Nebula, Inc.
# All rights reserved. # All rights reserved.
""" """
Views for managing volumes. Views for managing volumes.
""" """
from django.conf import settings from django.conf import settings
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.forms import ValidationError from django.forms import ValidationError
from django.utils.translation import ugettext_lazy as _ # noqa from django.utils.translation import ugettext_lazy as _ # noqa
from horizon import exceptions from horizon import exceptions
from horizon import forms from horizon import forms
from horizon import messages from horizon import messages
from openstack_dashboard import api from openstack_dashboard import api
from openstack_dashboard.api import cinder from openstack_dashboard.api import cinder
from openstack_dashboard.api import nova from openstack_dashboard.dashboards.project.instances import tables
from openstack_dashboard.dashboards.project.instances import tables
from starlingx_dashboard.api import nova as stx_nova
from starlingx_dashboard.api import nova as stx_nova
class CreateForm(forms.SelfHandlingForm):
class CreateForm(forms.SelfHandlingForm): tenantP = forms.ChoiceField(label=_("Project"), required=True)
tenantP = forms.ChoiceField(label=_("Project"), required=True) name = forms.CharField(max_length="255", label=_("Server Group Name"))
name = forms.CharField(max_length="255", label=_("Server Group Name")) policy = forms.ChoiceField(label=_("Policy"),
policy = forms.ChoiceField(label=_("Policy"), required=False,
required=False, widget=forms.Select(
widget=forms.Select( attrs={
attrs={ 'class': 'switchable',
'class': 'switchable', 'data-slug': 'policy_ht'}))
'data-slug': 'policy_ht'}))
is_best_effort = forms.BooleanField(label=_("Best Effort"), required=False)
is_best_effort = forms.BooleanField(label=_("Best Effort"), required=False)
group_size = forms.IntegerField(
group_size = forms.IntegerField( min_value=1,
min_value=1, label=_("Max Group Size (Instances)"),
label=_("Max Group Size (Instances)"), required=False,
required=False, widget=forms.TextInput(
widget=forms.TextInput( attrs={
attrs={ 'class': 'switchable switched',
'class': 'switchable switched', 'data-switch-on': 'policy_ht',
'data-switch-on': 'policy_ht', 'data-policy_ht-anti-affinity': 'Max Group Size (Instances)',
'data-policy_ht-anti-affinity': 'Max Group Size (Instances)', 'data-policy_ht-affinity': 'Max Group Size (Instances)'}))
'data-policy_ht-affinity': 'Max Group Size (Instances)'}))
group_size_ht = forms.IntegerField(
group_size_ht = forms.IntegerField( label=_("Max Group Size (Instances)"),
label=_("Max Group Size (Instances)"), required=False,
required=False, widget=forms.TextInput(
widget=forms.TextInput( attrs={
attrs={ 'readonly': 'readonly',
'readonly': 'readonly', 'class': 'switchable switched',
'class': 'switchable switched', 'data-switch-on': 'policy_ht',
'data-switch-on': 'policy_ht', 'data-policy_ht-affinity-hyperthread':
'data-policy_ht-affinity-hyperthread': 'Max Group Size (Instances)'}))
'Max Group Size (Instances)'}))
def __init__(self, request, *args, **kwargs):
def __init__(self, request, *args, **kwargs): super(CreateForm, self).__init__(request, *args, **kwargs)
super(CreateForm, self).__init__(request, *args, **kwargs) self.fields['policy'].choices = [("anti-affinity", "anti-affinity"),
self.fields['policy'].choices = [("anti-affinity", "anti-affinity"), ("affinity", "affinity")]
("affinity", "affinity")]
# Populate available project_id/name choices
# Populate available project_id/name choices all_projects = []
all_projects = [] try:
try: # Get list of available projects.
# Get list of available projects. all_projects, has_more = api.keystone.tenant_list(request)
all_projects, has_more = api.keystone.tenant_list(request)
projects_list = [(project.id, project.name)
projects_list = [(project.id, project.name) for project in all_projects]
for project in all_projects]
except Exception:
except Exception: projects_list = []
projects_list = [] exceptions.handle(self.request,
exceptions.handle(self.request, _('Unable to retrieve list of tenants.'))
_('Unable to retrieve list of tenants.'))
self.fields['tenantP'].choices = projects_list
self.fields['tenantP'].choices = projects_list
def handle(self, request, data):
def handle(self, request, data): try:
try: policy = data['policy']
policy = data['policy'] policies = []
policies = [] if policy:
if policy: policies.append(policy)
policies.append(policy) metadata = {}
metadata = {} if data['is_best_effort']:
if data['is_best_effort']: metadata['wrs-sg:best_effort'] = "true"
metadata['wrs-sg:best_effort'] = "true" group_size = data['group_size']
group_size = data['group_size'] group_size_ht = data['group_size_ht']
group_size_ht = data['group_size_ht'] if group_size:
if group_size: metadata['wrs-sg:group_size'] = str(group_size)
metadata['wrs-sg:group_size'] = str(group_size) elif group_size_ht:
elif group_size_ht: metadata['wrs-sg:group_size'] = str(group_size_ht)
metadata['wrs-sg:group_size'] = str(group_size_ht)
project_id = None
project_id = None if data['tenantP']:
if data['tenantP']: project_id = data['tenantP']
project_id = data['tenantP']
server_group = stx_nova.server_group_create(
server_group = stx_nova.server_group_create( request, data['name'], project_id, metadata, policies)
request, data['name'], project_id, metadata, policies) return server_group
return server_group
except ValidationError as e:
except ValidationError as e: self.api_error(e.messages[0])
self.api_error(e.messages[0]) return False
return False except Exception as e:
except Exception as e: exceptions.handle(request, ignore=True)
exceptions.handle(request, ignore=True) self.api_error(_("Unable to create server group."))
self.api_error(_("Unable to create server group.")) return False
return False
class AttachForm(forms.SelfHandlingForm):
class AttachForm(forms.SelfHandlingForm): instance = forms.ChoiceField(label=_("Attach to Server Group"),
instance = forms.ChoiceField(label=_("Attach to Server Group"), help_text=_("Select an server group to "
help_text=_("Select an server group to " "attach to."))
"attach to.")) device = forms.CharField(label=_("Device Name"))
device = forms.CharField(label=_("Device Name"))
def __init__(self, *args, **kwargs):
def __init__(self, *args, **kwargs): super(AttachForm, self).__init__(*args, **kwargs)
super(AttachForm, self).__init__(*args, **kwargs)
# Hide the device field if the hypervisor doesn't support it.
# Hide the device field if the hypervisor doesn't support it. hypervisor_features = getattr(settings,
hypervisor_features = getattr(settings, "OPENSTACK_HYPERVISOR_FEATURES", {})
"OPENSTACK_HYPERVISOR_FEATURES", {}) can_set_mount_point = hypervisor_features.get("can_set_mount_point",
can_set_mount_point = hypervisor_features.get("can_set_mount_point", True)
True) if not can_set_mount_point:
if not can_set_mount_point: self.fields['device'].widget = forms.widgets.HiddenInput()
self.fields['device'].widget = forms.widgets.HiddenInput() self.fields['device'].required = False
self.fields['device'].required = False
# populate volume_id
# populate volume_id volume = kwargs.get('initial', {}).get("volume", None)
volume = kwargs.get('initial', {}).get("volume", None) if volume:
if volume: volume_id = volume.id
volume_id = volume.id else:
else: volume_id = None
volume_id = None self.fields['volume_id'] = forms.CharField(widget=forms.HiddenInput(),
self.fields['volume_id'] = forms.CharField(widget=forms.HiddenInput(), initial=volume_id)
initial=volume_id)
# Populate instance choices
# Populate instance choices instance_list = kwargs.get('initial', {}).get('instances', [])
instance_list = kwargs.get('initial', {}).get('instances', []) instances = []
instances = [] for instance in instance_list:
for instance in instance_list: if instance.status in tables.ACTIVE_STATES and \
if instance.status in tables.ACTIVE_STATES and \ not any(instance.id == att["server_id"]
not any(instance.id == att["server_id"] for att in volume.attachments):
for att in volume.attachments): instances.append((instance.id, '%s (%s)' % (instance.name,
instances.append((instance.id, '%s (%s)' % (instance.name, instance.id)))
instance.id))) if instances:
if instances: instances.insert(0, ("", _("Select an instance")))
instances.insert(0, ("", _("Select an instance"))) else:
else: instances = (("", _("No instances available")),)
instances = (("", _("No instances available")),) self.fields['instance'].choices = instances
self.fields['instance'].choices = instances
def handle(self, request, data):
def handle(self, request, data): instance_choices = dict(self.fields['instance'].choices)
instance_choices = dict(self.fields['instance'].choices) instance_name = instance_choices.get(data['instance'],
instance_name = instance_choices.get(data['instance'], _("Unknown instance (None)"))
_("Unknown instance (None)")) # The name of the instance in the choices list has the ID appended to
# The name of the instance in the choices list has the ID appended to # it, so let's slice that off...
# it, so let's slice that off... instance_name = instance_name.rsplit(" (")[0]
instance_name = instance_name.rsplit(" (")[0] try:
try: attach = api.nova.instance_volume_attach(request,
attach = api.nova.instance_volume_attach(request, data['volume_id'],
data['volume_id'], data['instance'],
data['instance'], data.get('device', ''))
data.get('device', '')) volume = cinder.volume_get(request, data['volume_id'])
volume = cinder.volume_get(request, data['volume_id']) if not volume.display_name:
if not volume.display_name: volume_name = volume.id
volume_name = volume.id else:
else: volume_name = volume.display_name
volume_name = volume.display_name message = _('Attaching volume %(vol)s to instance '
message = _('Attaching volume %(vol)s to instance ' '%(inst)s on %(dev)s.') % {"vol": volume_name,
'%(inst)s on %(dev)s.') % {"vol": volume_name, "inst": instance_name,
"inst": instance_name, "dev": attach.device}
"dev": attach.device} messages.info(request, message)
messages.info(request, message) return True
return True except Exception:
except Exception: redirect = reverse("horizon:project:volumes:index")
redirect = reverse("horizon:project:volumes:index") exceptions.handle(request,
exceptions.handle(request, _('Unable to attach volume.'),
_('Unable to attach volume.'), redirect=redirect)
redirect=redirect)

View File

@ -1,40 +1,40 @@
# Copyright 2012 Nebula, Inc. # Copyright 2012 Nebula, Inc.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may # 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 # not use this file except in compliance with the License. You may obtain
# a copy of the License at # a copy of the License at
# #
# http://www.apache.org/licenses/LICENSE-2.0 # http://www.apache.org/licenses/LICENSE-2.0
# #
# Unless required by applicable law or agreed to in writing, software # Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
# #
# Copyright (c) 2013-2017 Wind River Systems, Inc. # Copyright (c) 2013-2018 Wind River Systems, Inc.
# #
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
import horizon import horizon
class ServerGroups(horizon.Panel): class ServerGroups(horizon.Panel):
name = _("Server Groups") name = _("Server Groups")
slug = 'server_groups' slug = 'server_groups'
# Server groups are wrs-specific # Server groups are wrs-specific
permissions = ('openstack.services.compute',) permissions = ('openstack.services.compute',)
policy_rules = (("compute", "context_is_admin"),) policy_rules = (("compute", "context_is_admin"),)
def allowed(self, context): def allowed(self, context):
if context['request'].user.services_region == 'SystemController': if context['request'].user.services_region == 'SystemController':
return False return False
else: else:
return super(ServerGroups, self).allowed(context) return super(ServerGroups, self).allowed(context)
def nav(self, context): def nav(self, context):
if context['request'].user.services_region == 'SystemController': if context['request'].user.services_region == 'SystemController':
return False return False
else: else:
return True return True

View File

@ -13,7 +13,7 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
# #
# Copyright (c) 2013-2017 Wind River Systems, Inc. # Copyright (c) 2013-2018 Wind River Systems, Inc.
# #
from django.core.urlresolvers import NoReverseMatch from django.core.urlresolvers import NoReverseMatch
@ -28,7 +28,6 @@ from horizon import exceptions
from horizon import tables from horizon import tables
from openstack_dashboard import api from openstack_dashboard import api
from openstack_dashboard.api import nova
from openstack_dashboard.dashboards.project.volumes.tables \ from openstack_dashboard.dashboards.project.volumes.tables \
import get_attachment_name import get_attachment_name
from openstack_dashboard.usage import quotas from openstack_dashboard.usage import quotas

View File

@ -1,53 +1,53 @@
# Copyright 2012 Nebula, Inc. # Copyright 2012 Nebula, Inc.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may # 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 # not use this file except in compliance with the License. You may obtain
# a copy of the License at # a copy of the License at
# #
# http://www.apache.org/licenses/LICENSE-2.0 # http://www.apache.org/licenses/LICENSE-2.0
# #
# Unless required by applicable law or agreed to in writing, software # Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
# #
# Copyright (c) 2013-2017 Wind River Systems, Inc. # Copyright (c) 2013-2018 Wind River Systems, Inc.
# #
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.utils.translation import ugettext_lazy as _ # noqa from django.utils.translation import ugettext_lazy as _ # noqa
from horizon import exceptions from horizon import exceptions
from horizon import tabs from horizon import tabs
from openstack_dashboard.api import nova from openstack_dashboard.api import nova
from starlingx_dashboard.api import nova as stx_nova from starlingx_dashboard.api import nova as stx_nova
class OverviewTab(tabs.Tab): class OverviewTab(tabs.Tab):
name = _("Overview") name = _("Overview")
slug = "overview" slug = "overview"
template_name = ("admin/server_groups/" template_name = ("admin/server_groups/"
"_detail_overview.html") "_detail_overview.html")
def get_context_data(self, request): def get_context_data(self, request):
server_group_id = self.tab_group.kwargs['server_group_id'] server_group_id = self.tab_group.kwargs['server_group_id']
try: try:
server_group = stx_nova.server_group_get(request, server_group_id) server_group = stx_nova.server_group_get(request, server_group_id)
server_group.members_display = [] server_group.members_display = []
for member in server_group.members: for member in server_group.members:
server_group.members_display.append( server_group.members_display.append(
dict(id=member, instance=nova.server_get(request, member))) dict(id=member, instance=nova.server_get(request, member)))
except Exception: except Exception:
redirect = reverse('horizon:admin:server_groups:index') redirect = reverse('horizon:admin:server_groups:index')
exceptions.handle(self.request, exceptions.handle(self.request,
_('Unable to retrieve server group details.'), _('Unable to retrieve server group details.'),
redirect=redirect) redirect=redirect)
return {'server_group': server_group} return {'server_group': server_group}
class ServerGroupDetailTabs(tabs.TabGroup): class ServerGroupDetailTabs(tabs.TabGroup):
slug = "server_group_details" slug = "server_group_details"
tabs = (OverviewTab,) tabs = (OverviewTab,)

View File

@ -1,32 +1,32 @@
# Copyright 2012 Nebula, Inc. # Copyright 2012 Nebula, Inc.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may # 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 # not use this file except in compliance with the License. You may obtain
# a copy of the License at # a copy of the License at
# #
# http://www.apache.org/licenses/LICENSE-2.0 # http://www.apache.org/licenses/LICENSE-2.0
# #
# Unless required by applicable law or agreed to in writing, software # Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
# #
# Copyright (c) 2013-2017 Wind River Systems, Inc. # Copyright (c) 2013-2018 Wind River Systems, Inc.
# #
from django.conf.urls import url from django.conf.urls import url
from starlingx_dashboard.dashboards.admin.server_groups import views from starlingx_dashboard.dashboards.admin.server_groups import views
urlpatterns = [ urlpatterns = [
url(r'^$', views.IndexView.as_view(), name='index'), url(r'^$', views.IndexView.as_view(), name='index'),
url(r'^create/$', views.CreateView.as_view(), name='create'), url(r'^create/$', views.CreateView.as_view(), name='create'),
url(r'^(?P<server_group_id>[^/]+)/attach/$', url(r'^(?P<server_group_id>[^/]+)/attach/$',
views.EditAttachmentsView.as_view(), views.EditAttachmentsView.as_view(),
name='attach'), name='attach'),
url(r'^(?P<server_group_id>[^/]+)/$', url(r'^(?P<server_group_id>[^/]+)/$',
views.DetailView.as_view(), views.DetailView.as_view(),
name='detail') name='detail')
] ]

View File

@ -1,148 +1,148 @@
# Copyright 2012 Nebula, Inc. # Copyright 2012 Nebula, Inc.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may # 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 # not use this file except in compliance with the License. You may obtain
# a copy of the License at # a copy of the License at
# #
# http://www.apache.org/licenses/LICENSE-2.0 # http://www.apache.org/licenses/LICENSE-2.0
# #
# Unless required by applicable law or agreed to in writing, software # Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
# #
# Copyright (c) 2013-2017 Wind River Systems, Inc. # Copyright (c) 2013-2018 Wind River Systems, Inc.
# #
""" """
Views for managing server groups. Views for managing server groups.
""" """
from django.core.urlresolvers import reverse_lazy # noqa from django.core.urlresolvers import reverse_lazy # noqa
from django.utils.translation import ugettext_lazy as _ # noqa from django.utils.translation import ugettext_lazy as _ # noqa
from horizon import exceptions from horizon import exceptions
from horizon import forms from horizon import forms
from horizon import tables from horizon import tables
from horizon import tabs from horizon import tabs
from openstack_dashboard import api from openstack_dashboard import api
from openstack_dashboard.usage import quotas from openstack_dashboard.usage import quotas
from starlingx_dashboard import api as stx_api from starlingx_dashboard import api as stx_api
from starlingx_dashboard.dashboards.admin.server_groups \ from starlingx_dashboard.dashboards.admin.server_groups \
import forms as admin_forms import forms as admin_forms
from starlingx_dashboard.dashboards.admin.server_groups \ from starlingx_dashboard.dashboards.admin.server_groups \
import tables as admin_tables import tables as admin_tables
from starlingx_dashboard.dashboards.admin.server_groups \ from starlingx_dashboard.dashboards.admin.server_groups \
import tabs as admin_tabs import tabs as admin_tabs
# server groups don't currently support pagination # server groups don't currently support pagination
class IndexView(tables.DataTableView): class IndexView(tables.DataTableView):
table_class = admin_tables.ServerGroupsTable table_class = admin_tables.ServerGroupsTable
template_name = 'admin/server_groups/index.html' template_name = 'admin/server_groups/index.html'
page_title = _("Server Groups") page_title = _("Server Groups")
def get_data(self): def get_data(self):
try: try:
server_groups = stx_api.nova.server_group_list( server_groups = stx_api.nova.server_group_list(
self.request, all_projects=True) self.request, all_projects=True)
except Exception: except Exception:
server_groups = [] server_groups = []
exceptions.handle(self.request, exceptions.handle(self.request,
_('Unable to retrieve server groups.')) _('Unable to retrieve server groups.'))
return server_groups return server_groups
class DetailView(tabs.TabView): class DetailView(tabs.TabView):
tab_group_class = admin_tabs.ServerGroupDetailTabs tab_group_class = admin_tabs.ServerGroupDetailTabs
template_name = 'admin/server_groups/detail.html' template_name = 'admin/server_groups/detail.html'
page_title = 'Server Group Details' page_title = 'Server Group Details'
class CreateView(forms.ModalFormView): class CreateView(forms.ModalFormView):
form_class = admin_forms.CreateForm form_class = admin_forms.CreateForm
template_name = 'admin/server_groups/create.html' template_name = 'admin/server_groups/create.html'
success_url = reverse_lazy("horizon:admin:server_groups:index") success_url = reverse_lazy("horizon:admin:server_groups:index")
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(CreateView, self).get_context_data(**kwargs) context = super(CreateView, self).get_context_data(**kwargs)
try: try:
context['usages'] = quotas.tenant_limit_usages(self.request) context['usages'] = quotas.tenant_limit_usages(self.request)
except Exception: except Exception:
exceptions.handle(self.request) exceptions.handle(self.request)
return context return context
class EditAttachmentsView(tables.DataTableView, forms.ModalFormView): class EditAttachmentsView(tables.DataTableView, forms.ModalFormView):
table_class = admin_tables.AttachmentsTable table_class = admin_tables.AttachmentsTable
form_class = admin_forms.AttachForm form_class = admin_forms.AttachForm
template_name = 'admin/server_groups/attach.html' template_name = 'admin/server_groups/attach.html'
success_url = reverse_lazy("horizon:admin:server_groups:index") success_url = reverse_lazy("horizon:admin:server_groups:index")
def get_object(self): def get_object(self):
if not hasattr(self, "_object"): if not hasattr(self, "_object"):
volume_id = self.kwargs['volume_id'] volume_id = self.kwargs['volume_id']
try: try:
self._object = api.cinder.volume_get(self.request, volume_id) self._object = api.cinder.volume_get(self.request, volume_id)
except Exception: except Exception:
self._object = None self._object = None
exceptions.handle(self.request, exceptions.handle(self.request,
_('Unable to retrieve volume information.')) _('Unable to retrieve volume information.'))
return self._object return self._object
def get_data(self): def get_data(self):
try: try:
volumes = self.get_object() volumes = self.get_object()
attachments = [att for att in volumes.attachments if att] attachments = [att for att in volumes.attachments if att]
except Exception: except Exception:
attachments = [] attachments = []
exceptions.handle(self.request, exceptions.handle(self.request,
_('Unable to retrieve volume information.')) _('Unable to retrieve volume information.'))
return attachments return attachments
def get_initial(self): def get_initial(self):
try: try:
instances, has_more = api.nova.server_list(self.request) instances, has_more = api.nova.server_list(self.request)
except Exception: except Exception:
instances = [] instances = []
exceptions.handle(self.request, exceptions.handle(self.request,
_("Unable to retrieve attachment information.")) _("Unable to retrieve attachment information."))
return {'volume': self.get_object(), return {'volume': self.get_object(),
'instances': instances} 'instances': instances}
def get_form(self): def get_form(self):
if not hasattr(self, "_form"): if not hasattr(self, "_form"):
form_class = self.get_form_class() form_class = self.get_form_class()
self._form = super(EditAttachmentsView, self).get_form(form_class) self._form = super(EditAttachmentsView, self).get_form(form_class)
return self._form return self._form
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(EditAttachmentsView, self).get_context_data(**kwargs) context = super(EditAttachmentsView, self).get_context_data(**kwargs)
context['form'] = self.get_form() context['form'] = self.get_form()
volume = self.get_object() volume = self.get_object()
if volume and volume.status == 'available': if volume and volume.status == 'available':
context['show_attach'] = True context['show_attach'] = True
else: else:
context['show_attach'] = False context['show_attach'] = False
context['volume'] = volume context['volume'] = volume
if self.request.is_ajax(): if self.request.is_ajax():
context['hide'] = True context['hide'] = True
return context return context
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
# Table action handling # Table action handling
handled = self.construct_tables() handled = self.construct_tables()
if handled: if handled:
return handled return handled
return self.render_to_response(self.get_context_data(**kwargs)) return self.render_to_response(self.get_context_data(**kwargs))
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
form = self.get_form() form = self.get_form()
if form.is_valid(): if form.is_valid():
return self.form_valid(form) return self.form_valid(form)
else: else:
return self.get(request, *args, **kwargs) return self.get(request, *args, **kwargs)

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2013-2016 Wind River Systems, Inc. # Copyright (c) 2013-2018 Wind River Systems, Inc.
# #
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# #
@ -57,7 +57,7 @@ class ApplyPatch(tables.BatchAction):
result = stx_api.patch.patch_apply_req(request, obj_ids) result = stx_api.patch.patch_apply_req(request, obj_ids)
messages.success(request, result) messages.success(request, result)
except Exception as ex: except Exception as ex:
messages.error(request, ex.message) messages.error(request, str(ex))
class RemovePatch(tables.BatchAction): class RemovePatch(tables.BatchAction):
@ -97,7 +97,7 @@ class RemovePatch(tables.BatchAction):
result = stx_api.patch.patch_remove_req(request, obj_ids) result = stx_api.patch.patch_remove_req(request, obj_ids)
messages.success(request, result) messages.success(request, result)
except Exception as ex: except Exception as ex:
messages.error(request, ex.message) messages.error(request, str(ex))
class DeletePatch(tables.BatchAction): class DeletePatch(tables.BatchAction):
@ -131,7 +131,7 @@ class DeletePatch(tables.BatchAction):
result = stx_api.patch.patch_delete_req(request, obj_ids) result = stx_api.patch.patch_delete_req(request, obj_ids)
messages.success(request, result) messages.success(request, result)
except Exception as ex: except Exception as ex:
messages.error(request, ex.message) messages.error(request, str(ex))
class UpdatePatchRow(tables.Row): class UpdatePatchRow(tables.Row):
@ -223,7 +223,8 @@ class CreateStrategy(tables.LinkAction):
def allowed(self, request, datum): def allowed(self, request, datum):
try: try:
# Only a single strategy (patch or upgrade) can exist at a time. # Only a single strategy (patch or upgrade) can exist at a time.
strategy = get_cached_strategy(request, stx_api.vim.STRATEGY_SW_PATCH, strategy = get_cached_strategy(request,
stx_api.vim.STRATEGY_SW_PATCH,
self.table) self.table)
if not strategy: if not strategy:
strategy = get_cached_strategy(request, strategy = get_cached_strategy(request,
@ -290,7 +291,7 @@ class DeleteStrategy(tables.Action):
messages.error(request, "Strategy delete failed") messages.error(request, "Strategy delete failed")
except Exception as ex: except Exception as ex:
LOG.exception(ex) LOG.exception(ex)
messages.error(request, ex.message) messages.error(request, str(ex))
class DeletePatchStrategy(DeleteStrategy): class DeletePatchStrategy(DeleteStrategy):
@ -338,7 +339,7 @@ class ApplyStrategy(tables.Action):
messages.error(request, "Strategy apply failed") messages.error(request, "Strategy apply failed")
except Exception as ex: except Exception as ex:
LOG.exception(ex) LOG.exception(ex)
messages.error(request, ex.message) messages.error(request, str(ex))
class ApplyPatchStrategy(ApplyStrategy): class ApplyPatchStrategy(ApplyStrategy):
@ -387,7 +388,7 @@ class AbortStrategy(tables.Action):
messages.error(request, "Strategy abort failed") messages.error(request, "Strategy abort failed")
except Exception as ex: except Exception as ex:
LOG.exception(ex) LOG.exception(ex)
messages.error(request, ex.message) messages.error(request, str(ex))
class AbortPatchStrategy(AbortStrategy): class AbortPatchStrategy(AbortStrategy):
@ -442,7 +443,8 @@ class ApplyStage(tables.BatchAction):
for obj_id in obj_ids: for obj_id in obj_ids:
try: try:
stage_id = obj_id.split('-', 1)[1] stage_id = obj_id.split('-', 1)[1]
result = stx_api.vim.apply_strategy(request, self.strategy_name, result = stx_api.vim.apply_strategy(request,
self.strategy_name,
stage_id) stage_id)
if result is None: if result is None:
messages.error(request, "Strategy stage %s apply failed" % messages.error(request, "Strategy stage %s apply failed" %
@ -453,7 +455,7 @@ class ApplyStage(tables.BatchAction):
stage_id) stage_id)
except Exception as ex: except Exception as ex:
LOG.exception(ex) LOG.exception(ex)
messages.error(request, ex.message) messages.error(request, str(ex))
class ApplyPatchStage(ApplyStage): class ApplyPatchStage(ApplyStage):
@ -503,7 +505,8 @@ class AbortStage(tables.BatchAction):
for obj_id in obj_ids: for obj_id in obj_ids:
try: try:
stage_id = obj_id.split('-', 1)[1] stage_id = obj_id.split('-', 1)[1]
result = stx_api.vim.abort_strategy(request, self.strategy_name, result = stx_api.vim.abort_strategy(request,
self.strategy_name,
stage_id) stage_id)
if result is None: if result is None:
messages.error(request, messages.error(request,
@ -514,7 +517,7 @@ class AbortStage(tables.BatchAction):
stage_id) stage_id)
except Exception as ex: except Exception as ex:
LOG.exception(ex) LOG.exception(ex)
messages.error(request, ex.message) messages.error(request, str(ex))
class AbortPatchStage(AbortStage): class AbortPatchStage(AbortStage):
@ -598,7 +601,10 @@ class UpdateStageRow(tables.Row):
def get_data(self, request, row_id): def get_data(self, request, row_id):
phase = row_id.split('-', 1)[0] phase = row_id.split('-', 1)[0]
stage_id = row_id.split('-', 1)[1] stage_id = row_id.split('-', 1)[1]
stage = stx_api.vim.get_stage(request, self.strategy_name, phase, stage_id) stage = stx_api.vim.get_stage(request,
self.strategy_name,
phase,
stage_id)
return stage return stage

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2013-2016 Wind River Systems, Inc. # Copyright (c) 2013-2018 Wind River Systems, Inc.
# #
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# #
@ -62,7 +62,8 @@ class PatchOrchestrationTab(tabs.TableTab):
strategy = None strategy = None
try: try:
strategy = stx_api.vim.get_strategy(request, stx_api.vim.STRATEGY_SW_PATCH) strategy = stx_api.vim.get_strategy(request,
stx_api.vim.STRATEGY_SW_PATCH)
except Exception as ex: except Exception as ex:
LOG.exception(ex) LOG.exception(ex)
exceptions.handle(request, exceptions.handle(request,
@ -75,7 +76,8 @@ class PatchOrchestrationTab(tabs.TableTab):
request = self.request request = self.request
stages = [] stages = []
try: try:
stages = stx_api.vim.get_stages(request, stx_api.vim.STRATEGY_SW_PATCH) stages = stx_api.vim.get_stages(request,
stx_api.vim.STRATEGY_SW_PATCH)
except Exception: except Exception:
exceptions.handle(self.request, exceptions.handle(self.request,
_('Unable to retrieve stages list.')) _('Unable to retrieve stages list.'))
@ -100,8 +102,8 @@ class UpgradeOrchestrationTab(tabs.TableTab):
strategy = None strategy = None
try: try:
strategy = stx_api.vim.get_strategy(request, strategy = stx_api.vim.get_strategy(
stx_api.vim.STRATEGY_SW_UPGRADE) request, stx_api.vim.STRATEGY_SW_UPGRADE)
except Exception as ex: except Exception as ex:
LOG.exception(ex) LOG.exception(ex)
exceptions.handle(request, exceptions.handle(request,
@ -114,7 +116,8 @@ class UpgradeOrchestrationTab(tabs.TableTab):
request = self.request request = self.request
stages = [] stages = []
try: try:
stages = stx_api.vim.get_stages(request, stx_api.vim.STRATEGY_SW_UPGRADE) stages = stx_api.vim.get_stages(request,
stx_api.vim.STRATEGY_SW_UPGRADE)
except Exception: except Exception:
exceptions.handle(self.request, exceptions.handle(self.request,
_('Unable to retrieve stages list.')) _('Unable to retrieve stages list.'))

View File

@ -17,8 +17,6 @@ from horizon import exceptions
from horizon import forms from horizon import forms
from horizon import messages from horizon import messages
from openstack_dashboard import api
from starlingx_dashboard import api as stx_api from starlingx_dashboard import api as stx_api
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -904,9 +902,8 @@ class UpdateiStoragePools(forms.SelfHandlingForm):
LOG.debug(data) LOG.debug(data)
if send_to_sysinv: if send_to_sysinv:
my_storage = stx_api.sysinv.storpool_update(request, my_storage = stx_api.sysinv.storpool_update(
storage_config_uuid, request, storage_config_uuid, **data)
**data)
if my_storage: if my_storage:
msg = _( msg = _(

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2013-2017 Wind River Systems, Inc. # Copyright (c) 2013-2018 Wind River Systems, Inc.
# #
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# #
@ -11,8 +11,6 @@ from django.utils.translation import ugettext_lazy as _
from horizon import exceptions from horizon import exceptions
from horizon import tabs from horizon import tabs
from openstack_dashboard import api
from starlingx_dashboard import api as stx_api from starlingx_dashboard import api as stx_api
from starlingx_dashboard.dashboards.admin.system_config.address_pools import \ from starlingx_dashboard.dashboards.admin.system_config.address_pools import \
tables as address_pool_tables tables as address_pool_tables

View File

@ -15,8 +15,6 @@ from horizon import forms
from horizon import tables from horizon import tables
from horizon import tabs from horizon import tabs
from openstack_dashboard import api
from starlingx_dashboard import api as stx_api from starlingx_dashboard import api as stx_api
from starlingx_dashboard.dashboards.admin.system_config.forms \ from starlingx_dashboard.dashboards.admin.system_config.forms \
import CreateSDNController import CreateSDNController
@ -432,8 +430,8 @@ class UpdateSDNControllerView(forms.ModalFormView):
if not hasattr(self, "_object"): if not hasattr(self, "_object"):
controller_uuid = self.kwargs['uuid'] controller_uuid = self.kwargs['uuid']
try: try:
self._object = stx_api.sysinv.sdn_controller_get(self.request, self._object = stx_api.sysinv.sdn_controller_get(
controller_uuid) self.request, controller_uuid)
except Exception: except Exception:
redirect = self.success_url redirect = self.success_url
msg = _('Unable to retrieve SDN controller details.') msg = _('Unable to retrieve SDN controller details.')

View File

@ -30,4 +30,5 @@ class DCAdmin(horizon.Dashboard):
return super(DCAdmin, self).allowed(context) return super(DCAdmin, self).allowed(context)
horizon.register(DCAdmin) horizon.register(DCAdmin)

View File

@ -115,7 +115,7 @@ class DeleteCloudPatchStrategy(tables.Action):
messages.error(request, "Strategy delete failed") messages.error(request, "Strategy delete failed")
except Exception as ex: except Exception as ex:
LOG.exception(ex) LOG.exception(ex)
messages.error(request, ex.message) messages.error(request, str(ex))
class ApplyCloudPatchStrategy(tables.Action): class ApplyCloudPatchStrategy(tables.Action):
@ -151,7 +151,7 @@ class ApplyCloudPatchStrategy(tables.Action):
messages.error(request, "Strategy apply failed") messages.error(request, "Strategy apply failed")
except Exception as ex: except Exception as ex:
LOG.exception(ex) LOG.exception(ex)
messages.error(request, ex.message) messages.error(request, str(ex))
class AbortCloudPatchStrategy(tables.Action): class AbortCloudPatchStrategy(tables.Action):
@ -190,7 +190,7 @@ class AbortCloudPatchStrategy(tables.Action):
messages.error(request, "Strategy abort failed") messages.error(request, "Strategy abort failed")
except Exception as ex: except Exception as ex:
LOG.exception(ex) LOG.exception(ex)
messages.error(request, ex.message) messages.error(request, str(ex))
STEP_STATE_CHOICES = ( STEP_STATE_CHOICES = (

View File

@ -1,180 +1,180 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may # 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 # not use this file except in compliance with the License. You may obtain
# a copy of the License at # a copy of the License at
# #
# http://www.apache.org/licenses/LICENSE-2.0 # http://www.apache.org/licenses/LICENSE-2.0
# #
# Unless required by applicable law or agreed to in writing, software # Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
# #
# Copyright (c) 2013-2017 Wind River Systems, Inc. # Copyright (c) 2013-2018 Wind River Systems, Inc.
# #
# Copyright 2012 Nebula, Inc. # Copyright 2012 Nebula, Inc.
# All rights reserved. # All rights reserved.
""" """
Views for managing volumes. Views for managing volumes.
""" """
from django.conf import settings from django.conf import settings
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.forms import ValidationError from django.forms import ValidationError
from django.utils.translation import ugettext_lazy as _ # noqa from django.utils.translation import ugettext_lazy as _ # noqa
from horizon import exceptions from horizon import exceptions
from horizon import forms from horizon import forms
from horizon import messages from horizon import messages
from openstack_dashboard import api from openstack_dashboard import api
from openstack_dashboard.api import cinder from openstack_dashboard.api import cinder
from openstack_dashboard.dashboards.project.instances import tables from openstack_dashboard.dashboards.project.instances import tables
from starlingx_dashboard.api import nova as stx_nova from starlingx_dashboard.api import nova as stx_nova
class CreateForm(forms.SelfHandlingForm): class CreateForm(forms.SelfHandlingForm):
name = forms.CharField(max_length="255", label=_("Server Group Name")) name = forms.CharField(max_length="255", label=_("Server Group Name"))
policy = forms.ChoiceField(label=_("Policy"), policy = forms.ChoiceField(label=_("Policy"),
required=False, required=False,
widget=forms.Select( widget=forms.Select(
attrs={ attrs={
'class': 'switchable', 'class': 'switchable',
'data-slug': 'policy_ht'})) 'data-slug': 'policy_ht'}))
is_best_effort = forms.BooleanField(label=_("Best Effort"), required=False) is_best_effort = forms.BooleanField(label=_("Best Effort"), required=False)
group_size = forms.IntegerField( group_size = forms.IntegerField(
min_value=1, min_value=1,
label=_("Max Group Size (Instances)"), label=_("Max Group Size (Instances)"),
required=False, required=False,
widget=forms.TextInput( widget=forms.TextInput(
attrs={ attrs={
'class': 'switchable switched', 'class': 'switchable switched',
'data-switch-on': 'policy_ht', 'data-switch-on': 'policy_ht',
'data-policy_ht-anti-affinity': 'Max Group Size (Instances)', 'data-policy_ht-anti-affinity': 'Max Group Size (Instances)',
'data-policy_ht-affinity': 'Max Group Size (Instances)'})) 'data-policy_ht-affinity': 'Max Group Size (Instances)'}))
group_size_ht = forms.IntegerField( group_size_ht = forms.IntegerField(
label=_("Max Group Size (Instances)"), label=_("Max Group Size (Instances)"),
required=False, required=False,
widget=forms.TextInput( widget=forms.TextInput(
attrs={ attrs={
'readonly': 'readonly', 'readonly': 'readonly',
'class': 'switchable switched', 'class': 'switchable switched',
'data-switch-on': 'policy_ht', 'data-switch-on': 'policy_ht',
'data-policy_ht-affinity-hyperthread': 'data-policy_ht-affinity-hyperthread':
'Max Group Size (Instances)'})) 'Max Group Size (Instances)'}))
def __init__(self, request, *args, **kwargs): def __init__(self, request, *args, **kwargs):
super(CreateForm, self).__init__(request, *args, **kwargs) super(CreateForm, self).__init__(request, *args, **kwargs)
self.fields['policy'].choices = [("anti-affinity", "anti-affinity"), self.fields['policy'].choices = [("anti-affinity", "anti-affinity"),
("affinity", "affinity")] ("affinity", "affinity")]
def handle(self, request, data): def handle(self, request, data):
try: try:
project_id = self.request.user.tenant_id project_id = self.request.user.tenant_id
policy = data['policy'] policy = data['policy']
policies = [] policies = []
if policy: if policy:
policies.append(policy) policies.append(policy)
metadata = {} metadata = {}
if data['is_best_effort']: if data['is_best_effort']:
metadata['wrs-sg:best_effort'] = "true" metadata['wrs-sg:best_effort'] = "true"
group_size = data['group_size'] group_size = data['group_size']
group_size_ht = data['group_size_ht'] group_size_ht = data['group_size_ht']
if group_size: if group_size:
metadata['wrs-sg:group_size'] = str(group_size) metadata['wrs-sg:group_size'] = str(group_size)
elif group_size_ht: elif group_size_ht:
metadata['wrs-sg:group_size'] = str(group_size_ht) metadata['wrs-sg:group_size'] = str(group_size_ht)
kwargs = {'name': data['name'], kwargs = {'name': data['name'],
'policies': policies, 'policies': policies,
'metadata': metadata, 'metadata': metadata,
'project_id': project_id} 'project_id': project_id}
server_group = stx_nova.server_group_create(request, **kwargs) server_group = stx_nova.server_group_create(request, **kwargs)
return server_group return server_group
except ValidationError as e: except ValidationError as e:
self.api_error(e.messages[0]) self.api_error(e.messages[0])
return False return False
except Exception: except Exception:
exceptions.handle(request, ignore=True) exceptions.handle(request, ignore=True)
self.api_error(_("Unable to create server group.")) self.api_error(_("Unable to create server group."))
return False return False
class AttachForm(forms.SelfHandlingForm): class AttachForm(forms.SelfHandlingForm):
instance = forms.ChoiceField(label=_("Attach to Server Group"), instance = forms.ChoiceField(label=_("Attach to Server Group"),
help_text=_("Select an server group to " help_text=_("Select an server group to "
"attach to.")) "attach to."))
device = forms.CharField(label=_("Device Name")) device = forms.CharField(label=_("Device Name"))
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(AttachForm, self).__init__(*args, **kwargs) super(AttachForm, self).__init__(*args, **kwargs)
# Hide the device field if the hypervisor doesn't support it. # Hide the device field if the hypervisor doesn't support it.
hypervisor_features = getattr(settings, hypervisor_features = getattr(settings,
"OPENSTACK_HYPERVISOR_FEATURES", "OPENSTACK_HYPERVISOR_FEATURES",
{}) {})
can_set_mount_point = hypervisor_features.get("can_set_mount_point", can_set_mount_point = hypervisor_features.get("can_set_mount_point",
True) True)
if not can_set_mount_point: if not can_set_mount_point:
self.fields['device'].widget = forms.widgets.HiddenInput() self.fields['device'].widget = forms.widgets.HiddenInput()
self.fields['device'].required = False self.fields['device'].required = False
# populate volume_id # populate volume_id
volume = kwargs.get('initial', {}).get("volume", None) volume = kwargs.get('initial', {}).get("volume", None)
if volume: if volume:
volume_id = volume.id volume_id = volume.id
else: else:
volume_id = None volume_id = None
self.fields['volume_id'] = forms.CharField(widget=forms.HiddenInput(), self.fields['volume_id'] = forms.CharField(widget=forms.HiddenInput(),
initial=volume_id) initial=volume_id)
# Populate instance choices # Populate instance choices
instance_list = kwargs.get('initial', {}).get('instances', []) instance_list = kwargs.get('initial', {}).get('instances', [])
instances = [] instances = []
for instance in instance_list: for instance in instance_list:
if instance.status in tables.ACTIVE_STATES and \ if instance.status in tables.ACTIVE_STATES and \
not any(instance.id == att["server_id"] not any(instance.id == att["server_id"]
for att in volume.attachments): for att in volume.attachments):
instances.append((instance.id, '%s (%s)' % (instance.name, instances.append((instance.id, '%s (%s)' % (instance.name,
instance.id))) instance.id)))
if instances: if instances:
instances.insert(0, ("", _("Select an instance"))) instances.insert(0, ("", _("Select an instance")))
else: else:
instances = (("", _("No instances available")),) instances = (("", _("No instances available")),)
self.fields['instance'].choices = instances self.fields['instance'].choices = instances
def handle(self, request, data): def handle(self, request, data):
instance_choices = dict(self.fields['instance'].choices) instance_choices = dict(self.fields['instance'].choices)
instance_name = instance_choices.get(data['instance'], instance_name = instance_choices.get(data['instance'],
_("Unknown instance (None)")) _("Unknown instance (None)"))
# The name of the instance in the choices list has the ID appended to # The name of the instance in the choices list has the ID appended to
# it, so let's slice that off... # it, so let's slice that off...
instance_name = instance_name.rsplit(" (")[0] instance_name = instance_name.rsplit(" (")[0]
try: try:
attach = api.nova.instance_volume_attach(request, attach = api.nova.instance_volume_attach(request,
data['volume_id'], data['volume_id'],
data['instance'], data['instance'],
data.get('device', '')) data.get('device', ''))
volume = cinder.volume_get(request, data['volume_id']) volume = cinder.volume_get(request, data['volume_id'])
if not volume.display_name: if not volume.display_name:
volume_name = volume.id volume_name = volume.id
else: else:
volume_name = volume.display_name volume_name = volume.display_name
message = _('Attaching volume %(vol)s to instance ' message = _('Attaching volume %(vol)s to instance '
'%(inst)s on %(dev)s.') % {"vol": volume_name, '%(inst)s on %(dev)s.') % {"vol": volume_name,
"inst": instance_name, "inst": instance_name,
"dev": attach.device} "dev": attach.device}
messages.info(request, message) messages.info(request, message)
return True return True
except Exception: except Exception:
redirect = reverse("horizon:project:volumes:index") redirect = reverse("horizon:project:volumes:index")
exceptions.handle(request, exceptions.handle(request,
_('Unable to attach volume.'), _('Unable to attach volume.'),
redirect=redirect) redirect=redirect)

View File

@ -1,45 +1,45 @@
# Copyright 2012 Nebula, Inc. # Copyright 2012 Nebula, Inc.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may # 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 # not use this file except in compliance with the License. You may obtain
# a copy of the License at # a copy of the License at
# #
# http://www.apache.org/licenses/LICENSE-2.0 # http://www.apache.org/licenses/LICENSE-2.0
# #
# Unless required by applicable law or agreed to in writing, software # Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
# #
# Copyright (c) 2013-2017 Wind River Systems, Inc. # Copyright (c) 2013-2018 Wind River Systems, Inc.
# #
from django.utils.translation import ugettext_lazy as _ # noqa from django.utils.translation import ugettext_lazy as _ # noqa
import horizon import horizon
from openstack_dashboard.api import base from openstack_dashboard.api import base
from openstack_dashboard.dashboards.project import dashboard from openstack_dashboard.dashboards.project import dashboard
class ServerGroups(horizon.Panel): class ServerGroups(horizon.Panel):
name = _("Server Groups") name = _("Server Groups")
slug = 'server_groups' slug = 'server_groups'
# Server groups are wrs-specific # Server groups are wrs-specific
permissions = ('openstack.services.platform',) permissions = ('openstack.services.platform',)
def allowed(self, context): def allowed(self, context):
if not base.is_service_enabled(context['request'], 'compute'): if not base.is_service_enabled(context['request'], 'compute'):
return False return False
else: else:
return super(ServerGroups, self).allowed(context) return super(ServerGroups, self).allowed(context)
def nav(self, context): def nav(self, context):
if not base.is_service_enabled(context['request'], 'compute'): if not base.is_service_enabled(context['request'], 'compute'):
return False return False
else: else:
return True return True
dashboard.Project.register(ServerGroups) dashboard.Project.register(ServerGroups)

View File

@ -1,287 +1,286 @@
# Copyright 2012 Nebula, Inc. # Copyright 2012 Nebula, Inc.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may # 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 # not use this file except in compliance with the License. You may obtain
# a copy of the License at # a copy of the License at
# #
# http://www.apache.org/licenses/LICENSE-2.0 # http://www.apache.org/licenses/LICENSE-2.0
# #
# Unless required by applicable law or agreed to in writing, software # Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
# #
# Copyright (c) 2013-2017 Wind River Systems, Inc. # Copyright (c) 2013-2018 Wind River Systems, Inc.
# #
from django.core.urlresolvers import NoReverseMatch from django.core.urlresolvers import NoReverseMatch
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.utils import html from django.utils import html
from django.utils import safestring from django.utils import safestring
from django.utils.translation import string_concat # noqa from django.utils.translation import string_concat # noqa
from django.utils.translation import ugettext_lazy as _ # noqa from django.utils.translation import ugettext_lazy as _ # noqa
from django.utils.translation import ungettext_lazy from django.utils.translation import ungettext_lazy
from horizon import exceptions from horizon import exceptions
from horizon import tables from horizon import tables
from openstack_dashboard import api from openstack_dashboard import api
from openstack_dashboard.api import nova from openstack_dashboard.dashboards.project.volumes.tables \
from openstack_dashboard.dashboards.project.volumes.tables \ import get_attachment_name
import get_attachment_name from openstack_dashboard.usage import quotas
from openstack_dashboard.usage import quotas
from starlingx_dashboard.api import nova as stx_nova
from starlingx_dashboard.api import nova as stx_nova
DELETABLE_STATES = ("available", "error")
DELETABLE_STATES = ("available", "error")
class DeleteServerGroup(tables.DeleteAction):
class DeleteServerGroup(tables.DeleteAction): data_type_singular = _("Server Group")
data_type_singular = _("Server Group") data_type_plural = _("Server Groups")
data_type_plural = _("Server Groups") action_past = _("Scheduled deletion of")
action_past = _("Scheduled deletion of")
@staticmethod
@staticmethod def action_present(count):
def action_present(count): return ungettext_lazy(
return ungettext_lazy( "Delete Server Group",
"Delete Server Group", "Delete Server Groups",
"Delete Server Groups", count
count )
)
@staticmethod
@staticmethod def action_past(count):
def action_past(count): return ungettext_lazy(
return ungettext_lazy( "Deleted Server Group",
"Deleted Server Group", "Deleted Server Groups",
"Deleted Server Groups", count
count )
)
def delete(self, request, obj_id):
def delete(self, request, obj_id): obj = self.table.get_object_by_id(obj_id)
obj = self.table.get_object_by_id(obj_id) name = self.table.get_object_display(obj)
name = self.table.get_object_display(obj)
try:
try: stx_nova.server_group_delete(request, obj_id)
stx_nova.server_group_delete(request, obj_id) except Exception:
except Exception: msg = _('Unable to delete group "%s" because it is not empty. '
msg = _('Unable to delete group "%s" because it is not empty. ' 'Either delete the member '
'Either delete the member ' 'instances or remove them from the group.')
'instances or remove them from the group.') exceptions.check_message(["group", "not", "empty."], msg % name)
exceptions.check_message(["group", "not", "empty."], msg % name) raise
raise
# maybe do a precheck to see if the group is empty first?
# maybe do a precheck to see if the group is empty first? def allowed(self, request, server_group=None):
def allowed(self, request, server_group=None): return True
return True
class CreateServerGroup(tables.LinkAction):
class CreateServerGroup(tables.LinkAction): name = "create"
name = "create" verbose_name = _("Create Server Group")
verbose_name = _("Create Server Group") url = "horizon:project:server_groups:create"
url = "horizon:project:server_groups:create" classes = ("ajax-modal", "btn-create")
classes = ("ajax-modal", "btn-create") icon = "plus"
icon = "plus"
def allowed(self, request, volume=None):
def allowed(self, request, volume=None): usages = quotas.tenant_quota_usages(request)
usages = quotas.tenant_quota_usages(request) if usages['server_groups']['available'] <= 0:
if usages['server_groups']['available'] <= 0: if "disabled" not in self.classes:
if "disabled" not in self.classes: self.classes = [c for c in self.classes] + ['disabled']
self.classes = [c for c in self.classes] + ['disabled'] self.verbose_name = string_concat(self.verbose_name, ' ',
self.verbose_name = string_concat(self.verbose_name, ' ', _("(Quota exceeded)"))
_("(Quota exceeded)")) else:
else: self.verbose_name = _("Create Server Group")
self.verbose_name = _("Create Server Group") classes = [c for c in self.classes if c != "disabled"]
classes = [c for c in self.classes if c != "disabled"] self.classes = classes
self.classes = classes return True
return True
class EditAttachments(tables.LinkAction):
class EditAttachments(tables.LinkAction): name = "attachments"
name = "attachments" verbose_name = _("Edit Attachments")
verbose_name = _("Edit Attachments") url = "horizon:project:server_groups:attach"
url = "horizon:project:server_groups:attach" classes = ("ajax-modal", "btn-edit")
classes = ("ajax-modal", "btn-edit")
def allowed(self, request, server_group=None):
def allowed(self, request, server_group=None): return True # volume.status in ("available", "in-use")
return True # volume.status in ("available", "in-use")
class CreateSnapshot(tables.LinkAction):
class CreateSnapshot(tables.LinkAction): name = "snapshots"
name = "snapshots" verbose_name = _("Create Snapshot")
verbose_name = _("Create Snapshot") url = "horizon:project:server_groups:create_snapshot"
url = "horizon:project:server_groups:create_snapshot" classes = ("ajax-modal", "btn-camera")
classes = ("ajax-modal", "btn-camera")
def allowed(self, request, server_group=None):
def allowed(self, request, server_group=None): return True # server_group.status == "available"
return True # server_group.status == "available"
class UpdateRow(tables.Row):
class UpdateRow(tables.Row): ajax = True
ajax = True
def get_data(self, request, server_group_id):
def get_data(self, request, server_group_id): server_group = stx_nova.server_group_get(request, server_group_id)
server_group = stx_nova.server_group_get(request, server_group_id) if not server_group.name:
if not server_group.name: server_group.name = server_group_id
server_group.name = server_group_id return server_group
return server_group
def get_policies(server_group):
def get_policies(server_group): policies = ', '.join(server_group.policies)
policies = ', '.join(server_group.policies) return policies
return policies
def get_metadata(server_group):
def get_metadata(server_group): metadata_items = ['{}:{}'.format(x, y) for x, y in
metadata_items = ['{}:{}'.format(x, y) for x, y in server_group.metadata.items()]
server_group.metadata.items()] metadata = ', '.join(metadata_items)
metadata = ', '.join(metadata_items) return metadata
return metadata
def get_member_name(request, server_id):
def get_member_name(request, server_id): try:
try: server = api.nova.server_get(request, server_id)
server = api.nova.server_get(request, server_id) name = server.name
name = server.name except Exception:
except Exception: name = None
name = None exceptions.handle(request, _("Unable to retrieve "
exceptions.handle(request, _("Unable to retrieve " "member information."))
"member information.")) # try and get a URL
# try and get a URL try:
try: url = reverse("horizon:project:instances:detail", args=(server_id,))
url = reverse("horizon:project:instances:detail", args=(server_id,)) instance = '<a href="%s">%s</a>' % (url, html.escape(name))
instance = '<a href="%s">%s</a>' % (url, html.escape(name)) except NoReverseMatch:
except NoReverseMatch: instance = name
instance = name return instance
return instance
class MemberColumn(tables.Column):
class MemberColumn(tables.Column): """Customized column class
"""Customized column class
Customized column class that does complex processing on the instances
Customized column class that does complex processing on the instances in a server group. This was substantially copied
in a server group. This was substantially copied from the volume equivalent.
from the volume equivalent. """
"""
def get_raw_data(self, server_group):
def get_raw_data(self, server_group): request = self.table.request
request = self.table.request link = _('%(name)s (%(id)s)')
link = _('%(name)s (%(id)s)') members = []
members = [] for member in server_group.members:
for member in server_group.members: member_id = member
member_id = member name = get_member_name(request, member)
name = get_member_name(request, member) vals = {"name": name, "id": member_id}
vals = {"name": name, "id": member_id} members.append(link % vals)
members.append(link % vals) return safestring.mark_safe(", ".join(members))
return safestring.mark_safe(", ".join(members))
def get_server_group_type(server_group):
def get_server_group_type(server_group): return server_group.volume_type if server_group.volume_type != "None" \
return server_group.volume_type if server_group.volume_type != "None" \ else None
else None
class ServerGroupsFilterAction(tables.FilterAction):
class ServerGroupsFilterAction(tables.FilterAction): def filter(self, table, server_groups, filter_string):
def filter(self, table, server_groups, filter_string): """Naive case-insensitive search."""
"""Naive case-insensitive search.""" q = filter_string.lower()
q = filter_string.lower() return [group for group in server_groups
return [group for group in server_groups if q in group.display_name.lower()]
if q in group.display_name.lower()]
class ServerGroupsTable(tables.DataTable):
class ServerGroupsTable(tables.DataTable): name = tables.Column("name",
name = tables.Column("name", verbose_name=_("Group Name"),
verbose_name=_("Group Name"), link="horizon:project:server_groups:detail")
link="horizon:project:server_groups:detail") policies = tables.Column(get_policies,
policies = tables.Column(get_policies, verbose_name=_("Policies"))
verbose_name=_("Policies")) members = MemberColumn("members",
members = MemberColumn("members", verbose_name=_("Members"))
verbose_name=_("Members")) metadata = tables.Column(get_metadata,
metadata = tables.Column(get_metadata, verbose_name=_("Metadata"))
verbose_name=_("Metadata"))
class Meta(object):
class Meta(object): name = "server_groups"
name = "server_groups" verbose_name = _("Server Groups")
verbose_name = _("Server Groups") row_class = UpdateRow
row_class = UpdateRow table_actions = (
table_actions = ( CreateServerGroup, DeleteServerGroup, ServerGroupsFilterAction)
CreateServerGroup, DeleteServerGroup, ServerGroupsFilterAction) row_actions = (DeleteServerGroup,)
row_actions = (DeleteServerGroup,)
def get_object_display(self, obj):
def get_object_display(self, obj): return obj.name
return obj.name
class DetachServerGroup(tables.BatchAction):
class DetachServerGroup(tables.BatchAction): name = "detach"
name = "detach" action_present = _("Detach")
action_present = _("Detach") action_past = _("Detaching") # This action is asynchronous.
action_past = _("Detaching") # This action is asynchronous. data_type_singular = _("Server Group")
data_type_singular = _("Server Group") data_type_plural = _("Server Groups")
data_type_plural = _("Server Groups") classes = ('btn-danger', 'btn-detach')
classes = ('btn-danger', 'btn-detach')
@staticmethod
@staticmethod def action_present(count):
def action_present(count): return ungettext_lazy(
return ungettext_lazy( "Server Group",
"Server Group", "Server Groups",
"Server Groups", count
count )
)
@staticmethod
@staticmethod def action_past(count):
def action_past(count): return ungettext_lazy(
return ungettext_lazy( "Deleted Group",
"Deleted Group", "Deleted Groups",
"Deleted Groups", count
count )
)
def action(self, request, obj_id):
def action(self, request, obj_id): attachment = self.table.get_object_by_id(obj_id)
attachment = self.table.get_object_by_id(obj_id) api.nova.instance_server_group_detach(
api.nova.instance_server_group_detach( request,
request, attachment.get('server_id', None),
attachment.get('server_id', None), obj_id)
obj_id)
def get_success_url(self, request):
def get_success_url(self, request): return reverse('horizon:project:server_groups:index')
return reverse('horizon:project:server_groups:index')
class AttachedInstanceColumn(tables.Column):
class AttachedInstanceColumn(tables.Column): """Customized column class
"""Customized column class
Customized column class that does complex processing on the attachments
Customized column class that does complex processing on the attachments for a server group.
for a server group. """
"""
def get_raw_data(self, attachment):
def get_raw_data(self, attachment): request = self.table.request
request = self.table.request return safestring.mark_safe(get_attachment_name(request, attachment))
return safestring.mark_safe(get_attachment_name(request, attachment))
class AttachmentsTable(tables.DataTable):
class AttachmentsTable(tables.DataTable): instance = AttachedInstanceColumn(get_member_name,
instance = AttachedInstanceColumn(get_member_name, verbose_name=_("Instance"))
verbose_name=_("Instance")) device = tables.Column("device",
device = tables.Column("device", verbose_name=_("Device"))
verbose_name=_("Device"))
def get_object_id(self, obj):
def get_object_id(self, obj): return obj['id']
return obj['id']
def get_object_display(self, attachment):
def get_object_display(self, attachment): instance_name = get_attachment_name(self.request, attachment)
instance_name = get_attachment_name(self.request, attachment) vals = {"dev": attachment['device'],
vals = {"dev": attachment['device'], "instance_name": html.strip_tags(instance_name)}
"instance_name": html.strip_tags(instance_name)} return _("%(dev)s on instance %(instance_name)s") % vals
return _("%(dev)s on instance %(instance_name)s") % vals
def get_object_by_id(self, obj_id):
def get_object_by_id(self, obj_id): for obj in self.data:
for obj in self.data: if self.get_object_id(obj) == obj_id:
if self.get_object_id(obj) == obj_id: return obj
return obj raise ValueError('No match found for the id "%s".' % obj_id)
raise ValueError('No match found for the id "%s".' % obj_id)
class Meta(object):
class Meta(object): name = "attachments"
name = "attachments" verbose_name = _("Attachments")
verbose_name = _("Attachments") table_actions = (DetachServerGroup,)
table_actions = (DetachServerGroup,) row_actions = (DetachServerGroup,)
row_actions = (DetachServerGroup,)

View File

@ -1,53 +1,53 @@
# Copyright 2012 Nebula, Inc. # Copyright 2012 Nebula, Inc.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may # 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 # not use this file except in compliance with the License. You may obtain
# a copy of the License at # a copy of the License at
# #
# http://www.apache.org/licenses/LICENSE-2.0 # http://www.apache.org/licenses/LICENSE-2.0
# #
# Unless required by applicable law or agreed to in writing, software # Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
# #
# Copyright (c) 2013-2017 Wind River Systems, Inc. # Copyright (c) 2013-2018 Wind River Systems, Inc.
# #
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.utils.translation import ugettext_lazy as _ # noqa from django.utils.translation import ugettext_lazy as _ # noqa
from horizon import exceptions from horizon import exceptions
from horizon import tabs from horizon import tabs
from openstack_dashboard.api import nova from openstack_dashboard.api import nova
from starlingx_dashboard.api import nova as stx_nova from starlingx_dashboard.api import nova as stx_nova
class OverviewTab(tabs.Tab): class OverviewTab(tabs.Tab):
name = _("Overview") name = _("Overview")
slug = "overview" slug = "overview"
template_name = ("project/server_groups/" template_name = ("project/server_groups/"
"_detail_overview.html") "_detail_overview.html")
def get_context_data(self, request): def get_context_data(self, request):
server_group_id = self.tab_group.kwargs['server_group_id'] server_group_id = self.tab_group.kwargs['server_group_id']
try: try:
server_group = stx_nova.server_group_get(request, server_group_id) server_group = stx_nova.server_group_get(request, server_group_id)
server_group.members_display = [] server_group.members_display = []
for member in server_group.members: for member in server_group.members:
server_group.members_display.append( server_group.members_display.append(
dict(id=member, instance=nova.server_get(request, member))) dict(id=member, instance=nova.server_get(request, member)))
except Exception: except Exception:
redirect = reverse('horizon:project:server_groups:index') redirect = reverse('horizon:project:server_groups:index')
exceptions.handle(self.request, exceptions.handle(self.request,
_('Unable to retrieve server group details.'), _('Unable to retrieve server group details.'),
redirect=redirect) redirect=redirect)
return {'server_group': server_group} return {'server_group': server_group}
class ServerGroupDetailTabs(tabs.TabGroup): class ServerGroupDetailTabs(tabs.TabGroup):
slug = "server_group_details" slug = "server_group_details"
tabs = (OverviewTab,) tabs = (OverviewTab,)

View File

@ -1,32 +1,32 @@
# Copyright 2012 Nebula, Inc. # Copyright 2012 Nebula, Inc.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may # 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 # not use this file except in compliance with the License. You may obtain
# a copy of the License at # a copy of the License at
# #
# http://www.apache.org/licenses/LICENSE-2.0 # http://www.apache.org/licenses/LICENSE-2.0
# #
# Unless required by applicable law or agreed to in writing, software # Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
# #
# Copyright (c) 2013-2017 Wind River Systems, Inc. # Copyright (c) 2013-2018 Wind River Systems, Inc.
# #
from django.conf.urls import url from django.conf.urls import url
from starlingx_dashboard.dashboards.project.server_groups import views from starlingx_dashboard.dashboards.project.server_groups import views
urlpatterns = [ urlpatterns = [
url(r'^$', views.IndexView.as_view(), name='index'), url(r'^$', views.IndexView.as_view(), name='index'),
url(r'^create/$', views.CreateView.as_view(), name='create'), url(r'^create/$', views.CreateView.as_view(), name='create'),
url(r'^(?P<server_group_id>[^/]+)/attach/$', url(r'^(?P<server_group_id>[^/]+)/attach/$',
views.EditAttachmentsView.as_view(), views.EditAttachmentsView.as_view(),
name='attach'), name='attach'),
url(r'^(?P<server_group_id>[^/]+)/$', url(r'^(?P<server_group_id>[^/]+)/$',
views.DetailView.as_view(), views.DetailView.as_view(),
name='detail'), name='detail'),
] ]

View File

@ -1,148 +1,148 @@
# Copyright 2012 Nebula, Inc. # Copyright 2012 Nebula, Inc.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may # 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 # not use this file except in compliance with the License. You may obtain
# a copy of the License at # a copy of the License at
# #
# http://www.apache.org/licenses/LICENSE-2.0 # http://www.apache.org/licenses/LICENSE-2.0
# #
# Unless required by applicable law or agreed to in writing, software # Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
# #
# Copyright (c) 2013-2017 Wind River Systems, Inc. # Copyright (c) 2013-2018 Wind River Systems, Inc.
# #
""" """
Views for managing server groups. Views for managing server groups.
""" """
from django.core.urlresolvers import reverse_lazy # noqa from django.core.urlresolvers import reverse_lazy # noqa
from django.utils.translation import ugettext_lazy as _ # noqa from django.utils.translation import ugettext_lazy as _ # noqa
from horizon import exceptions from horizon import exceptions
from horizon import forms from horizon import forms
from horizon import tables from horizon import tables
from horizon import tabs from horizon import tabs
from openstack_dashboard import api from openstack_dashboard import api
from openstack_dashboard.usage import quotas from openstack_dashboard.usage import quotas
from starlingx_dashboard import api as stx_api from starlingx_dashboard import api as stx_api
from starlingx_dashboard.dashboards.project.server_groups \ from starlingx_dashboard.dashboards.project.server_groups \
import forms as project_forms import forms as project_forms
from starlingx_dashboard.dashboards.project.server_groups \ from starlingx_dashboard.dashboards.project.server_groups \
import tables as project_tables import tables as project_tables
from starlingx_dashboard.dashboards.project.server_groups \ from starlingx_dashboard.dashboards.project.server_groups \
import tabs as project_tabs import tabs as project_tabs
# server groups don't currently support pagination # server groups don't currently support pagination
class IndexView(tables.DataTableView): class IndexView(tables.DataTableView):
table_class = project_tables.ServerGroupsTable table_class = project_tables.ServerGroupsTable
template_name = 'project/server_groups/index.html' template_name = 'project/server_groups/index.html'
page_title = _("Server Groups") page_title = _("Server Groups")
def get_data(self): def get_data(self):
try: try:
server_groups = stx_api.nova.server_group_list( server_groups = stx_api.nova.server_group_list(
self.request) self.request)
except Exception: except Exception:
server_groups = [] server_groups = []
exceptions.handle(self.request, exceptions.handle(self.request,
_('Unable to retrieve server groups.')) _('Unable to retrieve server groups.'))
return server_groups return server_groups
class DetailView(tabs.TabView): class DetailView(tabs.TabView):
tab_group_class = project_tabs.ServerGroupDetailTabs tab_group_class = project_tabs.ServerGroupDetailTabs
template_name = 'project/server_groups/detail.html' template_name = 'project/server_groups/detail.html'
page_title = 'Server Group Details' page_title = 'Server Group Details'
class CreateView(forms.ModalFormView): class CreateView(forms.ModalFormView):
form_class = project_forms.CreateForm form_class = project_forms.CreateForm
template_name = 'project/server_groups/create.html' template_name = 'project/server_groups/create.html'
success_url = reverse_lazy("horizon:project:server_groups:index") success_url = reverse_lazy("horizon:project:server_groups:index")
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(CreateView, self).get_context_data(**kwargs) context = super(CreateView, self).get_context_data(**kwargs)
try: try:
context['usages'] = quotas.tenant_limit_usages(self.request) context['usages'] = quotas.tenant_limit_usages(self.request)
except Exception: except Exception:
exceptions.handle(self.request) exceptions.handle(self.request)
return context return context
class EditAttachmentsView(tables.DataTableView, forms.ModalFormView): class EditAttachmentsView(tables.DataTableView, forms.ModalFormView):
table_class = project_tables.AttachmentsTable table_class = project_tables.AttachmentsTable
form_class = project_forms.AttachForm form_class = project_forms.AttachForm
template_name = 'project/server_groups/attach.html' template_name = 'project/server_groups/attach.html'
success_url = reverse_lazy("horizon:project:server_groups:index") success_url = reverse_lazy("horizon:project:server_groups:index")
def get_object(self): def get_object(self):
if not hasattr(self, "_object"): if not hasattr(self, "_object"):
volume_id = self.kwargs['volume_id'] volume_id = self.kwargs['volume_id']
try: try:
self._object = api.cinder.volume_get(self.request, volume_id) self._object = api.cinder.volume_get(self.request, volume_id)
except Exception: except Exception:
self._object = None self._object = None
exceptions.handle(self.request, exceptions.handle(self.request,
_('Unable to retrieve volume information.')) _('Unable to retrieve volume information.'))
return self._object return self._object
def get_data(self): def get_data(self):
try: try:
volumes = self.get_object() volumes = self.get_object()
attachments = [att for att in volumes.attachments if att] attachments = [att for att in volumes.attachments if att]
except Exception: except Exception:
attachments = [] attachments = []
exceptions.handle(self.request, exceptions.handle(self.request,
_('Unable to retrieve volume information.')) _('Unable to retrieve volume information.'))
return attachments return attachments
def get_initial(self): def get_initial(self):
try: try:
instances, has_more = api.nova.server_list(self.request) instances, has_more = api.nova.server_list(self.request)
except Exception: except Exception:
instances = [] instances = []
exceptions.handle(self.request, exceptions.handle(self.request,
_("Unable to retrieve attachment information.")) _("Unable to retrieve attachment information."))
return {'volume': self.get_object(), return {'volume': self.get_object(),
'instances': instances} 'instances': instances}
def get_form(self): def get_form(self):
if not hasattr(self, "_form"): if not hasattr(self, "_form"):
form_class = self.get_form_class() form_class = self.get_form_class()
self._form = super(EditAttachmentsView, self).get_form(form_class) self._form = super(EditAttachmentsView, self).get_form(form_class)
return self._form return self._form
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(EditAttachmentsView, self).get_context_data(**kwargs) context = super(EditAttachmentsView, self).get_context_data(**kwargs)
context['form'] = self.get_form() context['form'] = self.get_form()
volume = self.get_object() volume = self.get_object()
if volume and volume.status == 'available': if volume and volume.status == 'available':
context['show_attach'] = True context['show_attach'] = True
else: else:
context['show_attach'] = False context['show_attach'] = False
context['volume'] = volume context['volume'] = volume
if self.request.is_ajax(): if self.request.is_ajax():
context['hide'] = True context['hide'] = True
return context return context
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
# Table action handling # Table action handling
handled = self.construct_tables() handled = self.construct_tables()
if handled: if handled:
return handled return handled
return self.render_to_response(self.get_context_data(**kwargs)) return self.render_to_response(self.get_context_data(**kwargs))
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
form = self.get_form() form = self.get_form()
if form.is_valid(): if form.is_valid():
return self.form_valid(form) return self.form_valid(form)
else: else:
return self.get(request, *args, **kwargs) return self.get(request, *args, **kwargs)

View File

@ -1,11 +1,11 @@
# The slug of the panel to be added to HORIZON_CONFIG. Required. # The slug of the panel to be added to HORIZON_CONFIG. Required.
PANEL = 'server_groups' PANEL = 'server_groups'
# The slug of the dashboard the PANEL associated with. Required. # The slug of the dashboard the PANEL associated with. Required.
PANEL_DASHBOARD = 'project' PANEL_DASHBOARD = 'project'
# The slug of the panel group the PANEL is associated with. # The slug of the panel group the PANEL is associated with.
PANEL_GROUP = 'compute' PANEL_GROUP = 'compute'
# A list of applications to be added to INSTALLED_APPS. # A list of applications to be added to INSTALLED_APPS.
# Python panel class of the PANEL to be added. # Python panel class of the PANEL to be added.
ADD_PANEL = \ ADD_PANEL = \
'starlingx_dashboard.dashboards.project.server_groups.panel.ServerGroups' 'starlingx_dashboard.dashboards.project.server_groups.panel.ServerGroups'

View File

@ -1,10 +1,10 @@
# The slug of the panel to be added to HORIZON_CONFIG. Required. # The slug of the panel to be added to HORIZON_CONFIG. Required.
PANEL = 'server_groups' PANEL = 'server_groups'
# The slug of the dashboard the PANEL associated with. Required. # The slug of the dashboard the PANEL associated with. Required.
PANEL_DASHBOARD = 'admin' PANEL_DASHBOARD = 'admin'
# The slug of the panel group the PANEL is associated with. # The slug of the panel group the PANEL is associated with.
PANEL_GROUP = 'compute' PANEL_GROUP = 'compute'
# Python panel class of the PANEL to be added. # Python panel class of the PANEL to be added.
ADD_PANEL = \ ADD_PANEL = \
'starlingx_dashboard.dashboards.admin.server_groups.panel.ServerGroups' 'starlingx_dashboard.dashboards.admin.server_groups.panel.ServerGroups'

View File

@ -1,2 +1,2 @@
from starlingx_dashboard.stx_horizon.tables.actions import FixedWithQueryFilter from starlingx_dashboard.stx_horizon.tables.actions import FixedWithQueryFilter # noqa
from starlingx_dashboard.stx_horizon.tables.actions import LimitAction from starlingx_dashboard.stx_horizon.tables.actions import LimitAction # noqa

View File

@ -16,8 +16,10 @@ DEFAULT_TABLE_LIMITS = [10, 20, 50, 100, 500, 1000]
class FixedWithQueryFilter(FilterAction): class FixedWithQueryFilter(FilterAction):
"""A FilterAction that visually renders like a combination """FilterAction
FixedFilterAction and a FilterAction of type "query.
A FilterAction that visually renders like a combination
FixedFilterAction and a FilterAction of type query.
Before extracting data from the filter, always ensure to first call Before extracting data from the filter, always ensure to first call
the method updateFromRequestDataToSession(..) which will copy current the method updateFromRequestDataToSession(..) which will copy current
@ -38,7 +40,9 @@ class FixedWithQueryFilter(FilterAction):
self.disabled_choices = [] self.disabled_choices = []
def _get_fieldFromGETorPOSTorSESSION(self, request, param_name): def _get_fieldFromGETorPOSTorSESSION(self, request, param_name):
"""Utility method for getting 'named" data (param_name) from either """Utility method
Utility method for getting 'named" data (param_name) from either
GET/POST or Session . GET/POST or Session .
IMPORTANT NOTE: Has the side-effect of storing the data into IMPORTANT NOTE: Has the side-effect of storing the data into
the session the session

View File

@ -1,5 +0,0 @@
#
# Copyright (c) 2018 Intel Corporation
#
# SPDX-License-Identifier: Apache-2.0
#

15
tox.ini
View File

@ -33,15 +33,26 @@ commands =
ignore = E501,E129 ignore = E501,E129
[flake8]
# H102 Apache 2.0 license header not found
# B301 Python 3 does not include `.iter*` methods on dictionaries.
# B005 Using .strip() with multi-character strings is misleading the reader.
ignore = H102, B301, B005
# H106 Dont put vim configuration in source files (off by default).
# H203 Use assertIs(Not)None to check for None (off by default).
# H904 Delay string interpolations at logging calls (off by default).
enable-extensions = H106,H203,H904
[testenv:pep8] [testenv:pep8]
basepython = python3 basepython = python3
usedevelop = False usedevelop = False
skip_install = True skip_install = True
deps = deps =
pep8 hacking
flake8-bugbear
flake8<3.6.0
commands = commands =
pep8 flake8
[testenv:venv] [testenv:venv]
basepython = python3 basepython = python3