moving code to overrides
This commit is contained in:
parent
d932640781
commit
1e0c123d5b
@ -1,2 +0,0 @@
|
|||||||
from tuskar_sat_ui.infrastructure import nodes
|
|
||||||
from tuskar_sat_ui.api import node
|
|
@ -1,24 +0,0 @@
|
|||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
from tuskar_ui.api import flavor
|
|
||||||
from tuskar_ui.api import heat
|
|
||||||
from tuskar_ui.api import node
|
|
||||||
from tuskar_ui.api import tuskar
|
|
||||||
|
|
||||||
|
|
||||||
__all__ = [
|
|
||||||
"flavor",
|
|
||||||
"heat",
|
|
||||||
"node",
|
|
||||||
"tuskar",
|
|
||||||
]
|
|
Binary file not shown.
@ -1,557 +0,0 @@
|
|||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
import logging
|
|
||||||
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
|
||||||
from horizon.utils import memoized
|
|
||||||
#from ironicclient.v1 import client as ironicclient
|
|
||||||
from novaclient.v1_1.contrib import baremetal
|
|
||||||
from openstack_dashboard.api import base
|
|
||||||
from openstack_dashboard.api import glance
|
|
||||||
from openstack_dashboard.api import nova
|
|
||||||
from openstack_dashboard.test.test_data import utils as test_utils
|
|
||||||
|
|
||||||
from tuskar_ui.cached_property import cached_property # noqa
|
|
||||||
from tuskar_ui.handle_errors import handle_errors # noqa
|
|
||||||
from tuskar_ui.test.test_data import heat_data
|
|
||||||
from tuskar_ui.test.test_data import node_data
|
|
||||||
from tuskar_ui import utils
|
|
||||||
|
|
||||||
|
|
||||||
TEST_DATA = test_utils.TestDataContainer()
|
|
||||||
node_data.data(TEST_DATA)
|
|
||||||
heat_data.data(TEST_DATA)
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
def baremetalclient(request):
|
|
||||||
nc = nova.novaclient(request)
|
|
||||||
return baremetal.BareMetalNodeManager(nc)
|
|
||||||
|
|
||||||
|
|
||||||
# FIXME(lsmola) This should be done in Horizon, they don't have caching
|
|
||||||
@memoized.memoized
|
|
||||||
def image_get(request, image_id):
|
|
||||||
"""Returns an Image object with metadata
|
|
||||||
|
|
||||||
Returns an Image object populated with metadata for image
|
|
||||||
with supplied identifier.
|
|
||||||
|
|
||||||
:param image_id: list of objects to be put into a dict
|
|
||||||
:type object_list: list
|
|
||||||
|
|
||||||
:return: object
|
|
||||||
:rtype: glanceclient.v1.images.Image
|
|
||||||
"""
|
|
||||||
image = glance.image_get(request, image_id)
|
|
||||||
return image
|
|
||||||
|
|
||||||
|
|
||||||
class IronicNode(base.APIResourceWrapper):
|
|
||||||
_attrs = ('id', 'uuid', 'instance_uuid', 'driver', 'driver_info',
|
|
||||||
'properties', 'power_state')
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def create(cls, request, ipmi_address, cpu, ram, local_disk,
|
|
||||||
mac_addresses, ipmi_username=None, ipmi_password=None):
|
|
||||||
"""Create a Node in Ironic
|
|
||||||
|
|
||||||
:param request: request object
|
|
||||||
:type request: django.http.HttpRequest
|
|
||||||
|
|
||||||
:param ipmi_address: IPMI address
|
|
||||||
:type ipmi_address: str
|
|
||||||
|
|
||||||
:param cpu: number of cores
|
|
||||||
:type cpu: int
|
|
||||||
|
|
||||||
:param ram: RAM in GB
|
|
||||||
:type ram: int
|
|
||||||
|
|
||||||
:param local_disk: local disk in TB
|
|
||||||
:type local_disk: int
|
|
||||||
|
|
||||||
:param mac_addresses: list of mac addresses
|
|
||||||
:type mac_addresses: list of str
|
|
||||||
|
|
||||||
:param ipmi_username: IPMI username
|
|
||||||
:type ipmi_username: str
|
|
||||||
|
|
||||||
:param ipmi_password: IPMI password
|
|
||||||
:type ipmi_password: str
|
|
||||||
|
|
||||||
:return: the created Node object
|
|
||||||
:rtype: tuskar_ui.api.node.IronicNode
|
|
||||||
"""
|
|
||||||
#node = ironicclient(request).node.create(
|
|
||||||
# driver='pxe_ipmitool',
|
|
||||||
# driver_info={'ipmi_address': ipmi_address,
|
|
||||||
# 'ipmi_username': ipmi_username,
|
|
||||||
# 'password': ipmi_password},
|
|
||||||
# properties={'cpu': cpu,
|
|
||||||
# 'ram': ram,
|
|
||||||
# 'local_disk': local_disk})
|
|
||||||
#for mac_address in mac_addresses:
|
|
||||||
# ironicclient(request).port.create(
|
|
||||||
# node_uuid=node.uuid,
|
|
||||||
# address=mac_address
|
|
||||||
# )
|
|
||||||
node = TEST_DATA.ironicclient_nodes.first()
|
|
||||||
return cls(node)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get(cls, request, uuid):
|
|
||||||
"""Return the IronicNode that matches the ID
|
|
||||||
|
|
||||||
:param request: request object
|
|
||||||
:type request: django.http.HttpRequest
|
|
||||||
|
|
||||||
:param uuid: ID of IronicNode to be retrieved
|
|
||||||
:type uuid: str
|
|
||||||
|
|
||||||
:return: matching IronicNode, or None if no IronicNode matches the ID
|
|
||||||
:rtype: tuskar_ui.api.node.IronicNode
|
|
||||||
"""
|
|
||||||
#node = ironicclient(request).nodes.get(uuid)
|
|
||||||
#return cls(node)
|
|
||||||
for node in IronicNode.list(request):
|
|
||||||
if node.uuid == uuid:
|
|
||||||
return node
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_by_instance_uuid(cls, request, instance_uuid):
|
|
||||||
"""Return the IronicNode associated with the instance ID
|
|
||||||
|
|
||||||
:param request: request object
|
|
||||||
:type request: django.http.HttpRequest
|
|
||||||
|
|
||||||
:param instance_uuid: ID of Instance that is deployed on the IronicNode
|
|
||||||
to be retrieved
|
|
||||||
:type instance_uuid: str
|
|
||||||
|
|
||||||
:return: matching IronicNode
|
|
||||||
:rtype: tuskar_ui.api.node.IronicNode
|
|
||||||
|
|
||||||
:raises: ironicclient.exc.HTTPNotFound if there is no IronicNode with
|
|
||||||
the matching instance UUID
|
|
||||||
"""
|
|
||||||
#node = ironicclient(request).nodes.get_by_instance_uuid(instance_uuid)
|
|
||||||
#return cls(node)
|
|
||||||
for node in IronicNode.list(request):
|
|
||||||
if node.instance_uuid == instance_uuid:
|
|
||||||
return node
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@handle_errors(_("Unable to retrieve nodes"), [])
|
|
||||||
def list(cls, request, associated=None):
|
|
||||||
"""Return a list of IronicNodes
|
|
||||||
|
|
||||||
:param request: request object
|
|
||||||
:type request: django.http.HttpRequest
|
|
||||||
|
|
||||||
:param associated: should we also retrieve all IronicNodes, only those
|
|
||||||
associated with an Instance, or only those not
|
|
||||||
associated with an Instance?
|
|
||||||
:type associated: bool
|
|
||||||
|
|
||||||
:return: list of IronicNodes, or an empty list if there are none
|
|
||||||
:rtype: list of tuskar_ui.api.node.IronicNode
|
|
||||||
"""
|
|
||||||
#nodes = ironicclient(request).nodes.list(
|
|
||||||
# associated=associated)
|
|
||||||
nodes = TEST_DATA.ironicclient_nodes.list()
|
|
||||||
if associated is not None:
|
|
||||||
if associated:
|
|
||||||
nodes = [node for node in nodes
|
|
||||||
if node.instance_uuid is not None]
|
|
||||||
else:
|
|
||||||
nodes = [node for node in nodes
|
|
||||||
if node.instance_uuid is None]
|
|
||||||
|
|
||||||
return [cls(node) for node in nodes]
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def delete(cls, request, uuid):
|
|
||||||
"""Remove the IronicNode matching the ID if it
|
|
||||||
exists; otherwise, does nothing.
|
|
||||||
|
|
||||||
:param request: request object
|
|
||||||
:type request: django.http.HttpRequest
|
|
||||||
|
|
||||||
:param uuid: ID of IronicNode to be removed
|
|
||||||
:type uuid: str
|
|
||||||
"""
|
|
||||||
#ironicclient(request).nodes.delete(uuid)
|
|
||||||
return
|
|
||||||
|
|
||||||
@cached_property
|
|
||||||
def addresses(self):
|
|
||||||
"""Return a list of port addresses associated with this IronicNode
|
|
||||||
|
|
||||||
:return: list of port addresses associated with this IronicNode, or
|
|
||||||
an empty list if no addresses are associated with
|
|
||||||
this IronicNode
|
|
||||||
:rtype: list of str
|
|
||||||
"""
|
|
||||||
ports = self.list_ports()
|
|
||||||
return [port.address for port in ports]
|
|
||||||
|
|
||||||
|
|
||||||
class BareMetalNode(base.APIResourceWrapper):
|
|
||||||
_attrs = ('id', 'uuid', 'instance_uuid', 'memory_mb', 'cpus', 'local_gb',
|
|
||||||
'task_state', 'pm_user', 'pm_address', 'interfaces')
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def create(cls, request, ipmi_address, cpu, ram, local_disk,
|
|
||||||
mac_addresses, ipmi_username=None, ipmi_password=None):
|
|
||||||
"""Create a Nova BareMetalNode
|
|
||||||
|
|
||||||
:param request: request object
|
|
||||||
:type request: django.http.HttpRequest
|
|
||||||
|
|
||||||
:param ipmi_address: IPMI address
|
|
||||||
:type ipmi_address: str
|
|
||||||
|
|
||||||
:param cpu: number of cores
|
|
||||||
:type cpu: int
|
|
||||||
|
|
||||||
:param ram: RAM in GB
|
|
||||||
:type ram: int
|
|
||||||
|
|
||||||
:param local_disk: local disk in TB
|
|
||||||
:type local_disk: int
|
|
||||||
|
|
||||||
:param mac_addresses: list of mac addresses
|
|
||||||
:type mac_addresses: list of str
|
|
||||||
|
|
||||||
:param ipmi_username: IPMI username
|
|
||||||
:type ipmi_username: str
|
|
||||||
|
|
||||||
:param ipmi_password: IPMI password
|
|
||||||
:type ipmi_password: str
|
|
||||||
|
|
||||||
:return: the created BareMetalNode object
|
|
||||||
:rtype: tuskar_ui.api.node.BareMetalNode
|
|
||||||
"""
|
|
||||||
#node = baremetalclient(request).create(
|
|
||||||
# 'undercloud',
|
|
||||||
# cpu,
|
|
||||||
# ram,
|
|
||||||
# local_disk,
|
|
||||||
# mac_addresses,
|
|
||||||
# pm_address=ipmi_address,
|
|
||||||
# pm_user=ipmi_username,
|
|
||||||
# pm_password=ipmi_password)
|
|
||||||
node = TEST_DATA.baremetalclient_nodes.first()
|
|
||||||
return cls(node)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get(cls, request, uuid):
|
|
||||||
"""Return the BareMetalNode that matches the ID
|
|
||||||
|
|
||||||
:param request: request object
|
|
||||||
:type request: django.http.HttpRequest
|
|
||||||
|
|
||||||
:param uuid: ID of BareMetalNode to be retrieved
|
|
||||||
:type uuid: str
|
|
||||||
|
|
||||||
:return: matching BareMetalNode, or None if no BareMetalNode matches
|
|
||||||
the ID
|
|
||||||
:rtype: tuskar_ui.api.node.BareMetalNode
|
|
||||||
"""
|
|
||||||
#node = baremetalclient(request).get(uuid)
|
|
||||||
#return cls(node)
|
|
||||||
for node in BareMetalNode.list(request):
|
|
||||||
if node.uuid == uuid:
|
|
||||||
return node
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_by_instance_uuid(cls, request, instance_uuid):
|
|
||||||
"""Return the BareMetalNode associated with the instance ID
|
|
||||||
|
|
||||||
:param request: request object
|
|
||||||
:type request: django.http.HttpRequest
|
|
||||||
|
|
||||||
:param instance_uuid: ID of Instance that is deployed on the
|
|
||||||
BareMetalNode to be retrieved
|
|
||||||
:type instance_uuid: str
|
|
||||||
|
|
||||||
:return: matching BareMetalNode
|
|
||||||
:rtype: tuskar_ui.api.node.BareMetalNode
|
|
||||||
|
|
||||||
:raises: ironicclient.exc.HTTPNotFound if there is no BareMetalNode
|
|
||||||
with the matching instance UUID
|
|
||||||
"""
|
|
||||||
#nodes = baremetalclient(request).list()
|
|
||||||
#node = next((n for n in nodes if instance_uuid == n.instance_uuid),
|
|
||||||
# None)
|
|
||||||
#return cls(node)
|
|
||||||
for node in BareMetalNode.list(request):
|
|
||||||
if node.instance_uuid == instance_uuid:
|
|
||||||
return node
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def list(cls, request, associated=None):
|
|
||||||
"""Return a list of BareMetalNodes
|
|
||||||
|
|
||||||
:param request: request object
|
|
||||||
:type request: django.http.HttpRequest
|
|
||||||
|
|
||||||
:param associated: should we also retrieve all BareMetalNodes, only
|
|
||||||
those associated with an Instance, or only those not
|
|
||||||
associated with an Instance?
|
|
||||||
:type associated: bool
|
|
||||||
|
|
||||||
:return: list of BareMetalNodes, or an empty list if there are none
|
|
||||||
:rtype: list of tuskar_ui.api.node.BareMetalNode
|
|
||||||
"""
|
|
||||||
#nodes = baremetalclient(request).list()
|
|
||||||
nodes = TEST_DATA.baremetalclient_nodes.list()
|
|
||||||
if associated is not None:
|
|
||||||
if associated:
|
|
||||||
nodes = [node for node in nodes
|
|
||||||
if node.instance_uuid is not None]
|
|
||||||
else:
|
|
||||||
nodes = [node for node in nodes
|
|
||||||
if node.instance_uuid is None]
|
|
||||||
return [cls(node) for node in nodes]
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def delete(cls, request, uuid):
|
|
||||||
"""Remove the BareMetalNode if it exists; otherwise, do nothing.
|
|
||||||
|
|
||||||
:param request: request object
|
|
||||||
:type request: django.http.HttpRequest
|
|
||||||
|
|
||||||
:param uuid: ID of BareMetalNode to be removed
|
|
||||||
:type uuid: str
|
|
||||||
"""
|
|
||||||
#baremetalclient(request).delete(uuid)
|
|
||||||
return
|
|
||||||
|
|
||||||
@cached_property
|
|
||||||
def power_state(self):
|
|
||||||
"""Return a power state of this BareMetalNode
|
|
||||||
|
|
||||||
:return: power state of this node
|
|
||||||
:rtype: str
|
|
||||||
"""
|
|
||||||
task_state_dict = {
|
|
||||||
'initializing': 'initializing',
|
|
||||||
'active': 'on',
|
|
||||||
'reboot': 'rebooting',
|
|
||||||
'building': 'building',
|
|
||||||
'deploying': 'deploying',
|
|
||||||
'prepared': 'prepared',
|
|
||||||
'deleting': 'deleting',
|
|
||||||
'deploy failed': 'deploy failed',
|
|
||||||
'deploy complete': 'deploy complete',
|
|
||||||
'deleted': 'deleted',
|
|
||||||
'error': 'error',
|
|
||||||
}
|
|
||||||
return task_state_dict.get(self.task_state, 'off')
|
|
||||||
|
|
||||||
@cached_property
|
|
||||||
def properties(self):
|
|
||||||
"""Return properties of this BareMetalNode
|
|
||||||
|
|
||||||
:return: return memory, cpus and local_disk properties
|
|
||||||
of this BareMetalNode, ram and local_disk properties
|
|
||||||
are in bytes
|
|
||||||
:rtype: dict of str
|
|
||||||
"""
|
|
||||||
return {
|
|
||||||
'ram': self.memory_mb * 1024.0 * 1024.0,
|
|
||||||
'cpu': self.cpus,
|
|
||||||
'local_disk': self.local_gb * 1024.0 * 1024.0 * 1024.0
|
|
||||||
}
|
|
||||||
|
|
||||||
@cached_property
|
|
||||||
def driver_info(self):
|
|
||||||
"""Return driver_info for this BareMetalNode
|
|
||||||
|
|
||||||
:return: return pm_address property of this BareMetalNode
|
|
||||||
:rtype: dict of str
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
ip_address = (self.instance._apiresource.addresses['ctlplane'][0]
|
|
||||||
['addr'])
|
|
||||||
except Exception:
|
|
||||||
LOG.error("Couldn't obtain IP address")
|
|
||||||
ip_address = None
|
|
||||||
|
|
||||||
return {
|
|
||||||
'ipmi_username': self.pm_user,
|
|
||||||
'ipmi_address': self.pm_address,
|
|
||||||
'ip_address': ip_address
|
|
||||||
}
|
|
||||||
|
|
||||||
@cached_property
|
|
||||||
def addresses(self):
|
|
||||||
"""Return a list of port addresses associated with this BareMetalNode
|
|
||||||
|
|
||||||
:return: list of port addresses associated with this BareMetalNode, or
|
|
||||||
an empty list if no addresses are associated with
|
|
||||||
this BareMetalNode
|
|
||||||
:rtype: list of str
|
|
||||||
"""
|
|
||||||
return [interface["address"] for interface in
|
|
||||||
self.interfaces]
|
|
||||||
|
|
||||||
|
|
||||||
class NodeClient(object):
|
|
||||||
def __init__(self, request):
|
|
||||||
ironic_enabled = base.is_service_enabled(request, 'baremetal')
|
|
||||||
|
|
||||||
if ironic_enabled:
|
|
||||||
self.node_class = IronicNode
|
|
||||||
else:
|
|
||||||
self.node_class = BareMetalNode
|
|
||||||
|
|
||||||
|
|
||||||
class Node(base.APIResourceWrapper):
|
|
||||||
_attrs = ('id', 'uuid', 'instance_uuid', 'driver', 'driver_info',
|
|
||||||
'properties', 'power_state', 'addresses')
|
|
||||||
|
|
||||||
def __init__(self, apiresource, request=None, **kwargs):
|
|
||||||
"""Initialize a Node
|
|
||||||
|
|
||||||
:param apiresource: apiresource we want to wrap
|
|
||||||
:type apiresource: novaclient.v1_1.contrib.baremetal.BareMetalNode
|
|
||||||
|
|
||||||
:param request: request
|
|
||||||
:type request: django.core.handlers.wsgi.WSGIRequest
|
|
||||||
|
|
||||||
:param instance: instance relation we want to cache
|
|
||||||
:type instance: openstack_dashboard.api.nova.Server
|
|
||||||
|
|
||||||
:return: Node object
|
|
||||||
:rtype: tusar_ui.api.node.Node
|
|
||||||
"""
|
|
||||||
super(Node, self).__init__(apiresource)
|
|
||||||
self._request = request
|
|
||||||
if 'instance' in kwargs:
|
|
||||||
self._instance = kwargs['instance']
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def create(cls, request, ipmi_address, cpu, ram, local_disk,
|
|
||||||
mac_addresses, ipmi_username=None, ipmi_password=None):
|
|
||||||
return cls(NodeClient(request).node_class.create(
|
|
||||||
request, ipmi_address, cpu, ram, local_disk,
|
|
||||||
mac_addresses, ipmi_username=ipmi_username,
|
|
||||||
ipmi_password=ipmi_password))
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@handle_errors(_("Unable to retrieve node"))
|
|
||||||
def get(cls, request, uuid):
|
|
||||||
node = NodeClient(request).node_class.get(request, uuid)
|
|
||||||
if node.instance_uuid is not None:
|
|
||||||
#server = nova.server_get(request, node.instance_uuid)
|
|
||||||
server = TEST_DATA.novaclient_servers.first()
|
|
||||||
return cls(node, instance=server, request=request)
|
|
||||||
|
|
||||||
return cls(node)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@handle_errors(_("Unable to retrieve node"))
|
|
||||||
def get_by_instance_uuid(cls, request, instance_uuid):
|
|
||||||
node = NodeClient(request).node_class.get_by_instance_uuid(
|
|
||||||
request, instance_uuid)
|
|
||||||
#server = nova.server_get(request, instance_uuid)
|
|
||||||
server = TEST_DATA.novaclient_servers.first()
|
|
||||||
return cls(node, instance=server, request=request)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@handle_errors(_("Unable to retrieve nodes"), [])
|
|
||||||
def list(cls, request, associated=None):
|
|
||||||
nodes = NodeClient(request).node_class.list(
|
|
||||||
request, associated=associated)
|
|
||||||
|
|
||||||
if associated is None or associated:
|
|
||||||
#servers = nova.server_list(request)[0]
|
|
||||||
servers = TEST_DATA.novaclient_servers.list()
|
|
||||||
servers_dict = utils.list_to_dict(servers)
|
|
||||||
nodes_with_instance = []
|
|
||||||
for n in nodes:
|
|
||||||
server = servers_dict.get(n.instance_uuid, None)
|
|
||||||
nodes_with_instance.append(cls(n, instance=server,
|
|
||||||
request=request))
|
|
||||||
return nodes_with_instance
|
|
||||||
else:
|
|
||||||
return [cls(node, request=request) for node in nodes]
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def delete(cls, request, uuid):
|
|
||||||
NodeClient(request).node_class.delete(request, uuid)
|
|
||||||
|
|
||||||
@cached_property
|
|
||||||
def instance(self):
|
|
||||||
"""Return the Nova Instance associated with this Node
|
|
||||||
|
|
||||||
:return: Nova Instance associated with this Node; or
|
|
||||||
None if there is no Instance associated with this
|
|
||||||
Node, or no matching Instance is found
|
|
||||||
:rtype: Instance
|
|
||||||
"""
|
|
||||||
if hasattr(self, '_instance'):
|
|
||||||
return self._instance
|
|
||||||
|
|
||||||
if self.instance_uuid:
|
|
||||||
#server = nova.server_get(self._request, self.instance_uuid)
|
|
||||||
server = TEST_DATA.novaclient_servers.first()
|
|
||||||
return server
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
@cached_property
|
|
||||||
def image_name(self):
|
|
||||||
"""Return image name of associated instance
|
|
||||||
|
|
||||||
Returns image name of instance associated with node
|
|
||||||
|
|
||||||
:return: Image name of instance
|
|
||||||
:rtype: string
|
|
||||||
"""
|
|
||||||
if self.instance is None:
|
|
||||||
return
|
|
||||||
return image_get(self._request, self.instance.image['id']).name
|
|
||||||
|
|
||||||
@cached_property
|
|
||||||
def instance_status(self):
|
|
||||||
return getattr(getattr(self, 'instance', None),
|
|
||||||
'status', None)
|
|
||||||
|
|
||||||
|
|
||||||
def filter_nodes(nodes, healthy=None):
|
|
||||||
"""Filters the list of Nodes and returns the filtered list.
|
|
||||||
|
|
||||||
:param nodes: list of tuskar_ui.api.node.Node objects to filter
|
|
||||||
:type nodes: list
|
|
||||||
:param healthy: retrieve all Nodes (healthy=None),
|
|
||||||
only the healthly ones (healthy=True),
|
|
||||||
or only those in an error state (healthy=False)
|
|
||||||
:type healthy: None or bool
|
|
||||||
:return: list of filtered tuskar_ui.api.node.Node objects
|
|
||||||
:rtype: list
|
|
||||||
"""
|
|
||||||
error_states = ('deploy failed', 'error',)
|
|
||||||
|
|
||||||
if healthy is not None:
|
|
||||||
if healthy:
|
|
||||||
nodes = [node for node in nodes
|
|
||||||
if node.power_state not in error_states]
|
|
||||||
else:
|
|
||||||
nodes = [node for node in nodes
|
|
||||||
if node.power_state in error_states]
|
|
||||||
return nodes
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,177 +0,0 @@
|
|||||||
# -*- coding: utf8 -*-
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
import json
|
|
||||||
|
|
||||||
from django.core.urlresolvers import reverse_lazy
|
|
||||||
from django import http
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
|
||||||
from django.views.generic import base
|
|
||||||
|
|
||||||
from horizon import forms as horizon_forms
|
|
||||||
from horizon import tabs as horizon_tabs
|
|
||||||
from horizon import views as horizon_views
|
|
||||||
|
|
||||||
from openstack_dashboard.api import base as api_base
|
|
||||||
from openstack_dashboard.dashboards.admin.metering import views as metering
|
|
||||||
|
|
||||||
from tuskar_ui import api
|
|
||||||
from tuskar_ui.infrastructure.nodes import forms
|
|
||||||
from tuskar_ui.infrastructure.nodes import tabs
|
|
||||||
|
|
||||||
|
|
||||||
class IndexView(horizon_tabs.TabbedTableView):
|
|
||||||
tab_group_class = tabs.NodeTabs
|
|
||||||
template_name = 'infrastructure/nodes/index.html'
|
|
||||||
|
|
||||||
def get_free_nodes_count(self):
|
|
||||||
free_nodes_count = len(api.node.Node.list(
|
|
||||||
self.request, associated=False))
|
|
||||||
return free_nodes_count
|
|
||||||
|
|
||||||
def get_deployed_nodes_count(self):
|
|
||||||
deployed_nodes_count = len(api.node.Node.list(self.request,
|
|
||||||
associated=True))
|
|
||||||
return deployed_nodes_count
|
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
|
||||||
context = super(IndexView, self).get_context_data(**kwargs)
|
|
||||||
|
|
||||||
context['free_nodes_count'] = self.get_free_nodes_count()
|
|
||||||
context['deployed_nodes_count'] = self.get_deployed_nodes_count()
|
|
||||||
context['nodes_count'] = (context['free_nodes_count'] +
|
|
||||||
context['deployed_nodes_count'])
|
|
||||||
|
|
||||||
return context
|
|
||||||
|
|
||||||
|
|
||||||
class RegisterView(horizon_forms.ModalFormView):
|
|
||||||
form_class = forms.NodeFormset
|
|
||||||
form_prefix = 'register_nodes'
|
|
||||||
template_name = 'infrastructure/nodes/register.html'
|
|
||||||
success_url = reverse_lazy(
|
|
||||||
'horizon:infrastructure:nodes:index')
|
|
||||||
|
|
||||||
def get_data(self):
|
|
||||||
return []
|
|
||||||
|
|
||||||
def get_form(self, form_class):
|
|
||||||
return form_class(self.request.POST or None,
|
|
||||||
initial=self.get_data(),
|
|
||||||
prefix=self.form_prefix)
|
|
||||||
|
|
||||||
|
|
||||||
class DetailView(horizon_views.APIView):
|
|
||||||
template_name = 'infrastructure/nodes/details.html'
|
|
||||||
|
|
||||||
def get_data(self, request, context, *args, **kwargs):
|
|
||||||
node_uuid = kwargs.get('node_uuid')
|
|
||||||
redirect = reverse_lazy('horizon:infrastructure:nodes:index')
|
|
||||||
node = api.node.Node.get(request, node_uuid, _error_redirect=redirect)
|
|
||||||
context['node'] = node
|
|
||||||
if api_base.is_service_enabled(request, 'metering'):
|
|
||||||
context['meters'] = (
|
|
||||||
('cpu', _('CPU')),
|
|
||||||
('disk', _('Disk')),
|
|
||||||
('network', _('Network Bandwidth (In)')),
|
|
||||||
('energy', _('Energy')),
|
|
||||||
('memory', _('Memory')),
|
|
||||||
('swap', _('Swap')),
|
|
||||||
('network-out', _('Network Bandwidth (Out)')),
|
|
||||||
('power', _('Power')),
|
|
||||||
)
|
|
||||||
|
|
||||||
return context
|
|
||||||
|
|
||||||
|
|
||||||
class PerformanceView(base.TemplateView):
|
|
||||||
def get(self, request, *args, **kwargs):
|
|
||||||
meter = request.GET.get('meter')
|
|
||||||
date_options = request.GET.get('date_options')
|
|
||||||
date_from = request.GET.get('date_from')
|
|
||||||
date_to = request.GET.get('date_to')
|
|
||||||
stats_attr = request.GET.get('stats_attr', 'avg')
|
|
||||||
group_by = request.GET.get('group_by')
|
|
||||||
|
|
||||||
meter_name = meter.replace(".", "_")
|
|
||||||
resource_name = 'id' if group_by == "project" else 'resource_id'
|
|
||||||
node_uuid = kwargs.get('node_uuid')
|
|
||||||
|
|
||||||
additional_query = [{'field': 'resource_id',
|
|
||||||
'op': 'eq',
|
|
||||||
'value': node_uuid}]
|
|
||||||
|
|
||||||
resources, unit = metering.query_data(
|
|
||||||
request=request,
|
|
||||||
date_from=date_from,
|
|
||||||
date_to=date_to,
|
|
||||||
date_options=date_options,
|
|
||||||
group_by=group_by,
|
|
||||||
meter=meter,
|
|
||||||
additional_query=additional_query)
|
|
||||||
series = metering.SamplesView._series_for_meter(resources,
|
|
||||||
resource_name,
|
|
||||||
meter_name,
|
|
||||||
stats_attr,
|
|
||||||
unit)
|
|
||||||
|
|
||||||
average = used = 0
|
|
||||||
tooltip_average = ''
|
|
||||||
|
|
||||||
if series:
|
|
||||||
values = [point['y'] for point in series[0]['data']]
|
|
||||||
average = sum(values) / len(values)
|
|
||||||
used = values[-1]
|
|
||||||
first_date = series[0]['data'][0]['x']
|
|
||||||
last_date = series[0]['data'][-1]['x']
|
|
||||||
tooltip_average = _(
|
|
||||||
'Average %(average)s %(unit)s<br> From: %(first_date)s, to: '
|
|
||||||
'%(last_date)s'
|
|
||||||
) % (dict(average=average, unit=unit, first_date=first_date,
|
|
||||||
last_date=last_date)
|
|
||||||
)
|
|
||||||
|
|
||||||
ret = {
|
|
||||||
'series': series,
|
|
||||||
'settings': {
|
|
||||||
'renderer': 'StaticAxes',
|
|
||||||
'yMin': 0,
|
|
||||||
'yMax': 100,
|
|
||||||
'higlight_last_point': True,
|
|
||||||
'auto_size': False,
|
|
||||||
'auto_resize': False,
|
|
||||||
'axes_x': False,
|
|
||||||
'axes_y': False,
|
|
||||||
'bar_chart_settings': {
|
|
||||||
'orientation': 'vertical',
|
|
||||||
'used_label_placement': 'left',
|
|
||||||
'width': 30,
|
|
||||||
'color_scale_domain': [0, 80, 80, 100],
|
|
||||||
'color_scale_range': [
|
|
||||||
'#0000FF',
|
|
||||||
'#0000FF',
|
|
||||||
'#FF0000',
|
|
||||||
'#FF0000'
|
|
||||||
],
|
|
||||||
'average_color_scale_domain': [0, 100],
|
|
||||||
'average_color_scale_range': ['#0000FF', '#0000FF']
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'stats': {
|
|
||||||
'average': average,
|
|
||||||
'used': used,
|
|
||||||
'tooltip_average': tooltip_average,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return http.HttpResponse(json.dumps(ret), mimetype='application/json')
|
|
Binary file not shown.
@ -1,219 +0,0 @@
|
|||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
from openstack_dashboard.test.test_data import utils as test_data_utils
|
|
||||||
|
|
||||||
from ironicclient.v1 import node
|
|
||||||
from ironicclient.v1 import port
|
|
||||||
from novaclient.v1_1.contrib import baremetal
|
|
||||||
|
|
||||||
|
|
||||||
def data(TEST):
|
|
||||||
|
|
||||||
# BareMetalNode
|
|
||||||
TEST.baremetalclient_nodes = test_data_utils.TestDataContainer()
|
|
||||||
bm_node_1 = baremetal.BareMetalNode(
|
|
||||||
baremetal.BareMetalNodeManager(None),
|
|
||||||
{'id': '1',
|
|
||||||
'uuid': 'd0ace338-a702-426a-b344-394ce861e070',
|
|
||||||
'instance_uuid': 'aa',
|
|
||||||
"service_host": "undercloud",
|
|
||||||
"cpus": 1,
|
|
||||||
"memory_mb": 4096,
|
|
||||||
"local_gb": 20,
|
|
||||||
'task_state': 'active',
|
|
||||||
"pm_address": None,
|
|
||||||
"pm_user": None,
|
|
||||||
"interfaces": [{"address": "52:54:00:90:38:01"},
|
|
||||||
{"address": "52:54:00:90:38:01"}],
|
|
||||||
})
|
|
||||||
bm_node_2 = baremetal.BareMetalNode(
|
|
||||||
baremetal.BareMetalNodeManager(None),
|
|
||||||
{'id': '2',
|
|
||||||
'uuid': 'bb-22',
|
|
||||||
'instance_uuid': 'bb',
|
|
||||||
"service_host": "undercloud",
|
|
||||||
"cpus": 1,
|
|
||||||
"memory_mb": 4096,
|
|
||||||
"local_gb": 20,
|
|
||||||
'task_state': 'active',
|
|
||||||
"pm_address": None,
|
|
||||||
"pm_user": None,
|
|
||||||
"interfaces": [{"address": "52:54:00:90:38:01"}],
|
|
||||||
})
|
|
||||||
bm_node_3 = baremetal.BareMetalNode(
|
|
||||||
baremetal.BareMetalNodeManager(None),
|
|
||||||
{'id': '3',
|
|
||||||
'uuid': 'cc-33',
|
|
||||||
'instance_uuid': 'cc',
|
|
||||||
"service_host": "undercloud",
|
|
||||||
"cpus": 1,
|
|
||||||
"memory_mb": 4096,
|
|
||||||
"local_gb": 20,
|
|
||||||
'task_state': 'reboot',
|
|
||||||
"pm_address": None,
|
|
||||||
"pm_user": None,
|
|
||||||
"interfaces": [{"address": "52:54:00:90:38:01"}],
|
|
||||||
})
|
|
||||||
bm_node_4 = baremetal.BareMetalNode(
|
|
||||||
baremetal.BareMetalNodeManager(None),
|
|
||||||
{'id': '4',
|
|
||||||
'uuid': 'cc-44',
|
|
||||||
'instance_uuid': 'cc',
|
|
||||||
"service_host": "undercloud",
|
|
||||||
"cpus": 1,
|
|
||||||
"memory_mb": 4096,
|
|
||||||
"local_gb": 20,
|
|
||||||
'task_state': 'active',
|
|
||||||
"pm_address": None,
|
|
||||||
"pm_user": None,
|
|
||||||
"interfaces": [{"address": "52:54:00:90:38:01"}],
|
|
||||||
})
|
|
||||||
bm_node_5 = baremetal.BareMetalNode(
|
|
||||||
baremetal.BareMetalNodeManager(None),
|
|
||||||
{'id': '5',
|
|
||||||
'uuid': 'dd-55',
|
|
||||||
'instance_uuid': 'dd',
|
|
||||||
"service_host": "undercloud",
|
|
||||||
"cpus": 1,
|
|
||||||
"memory_mb": 4096,
|
|
||||||
"local_gb": 20,
|
|
||||||
'task_state': 'error',
|
|
||||||
"pm_address": None,
|
|
||||||
"pm_user": None,
|
|
||||||
"interfaces": [{"address": "52:54:00:90:38:01"}],
|
|
||||||
})
|
|
||||||
TEST.baremetalclient_nodes.add(
|
|
||||||
bm_node_1, bm_node_2, bm_node_3, bm_node_4, bm_node_5)
|
|
||||||
|
|
||||||
# IronicNode
|
|
||||||
TEST.ironicclient_nodes = test_data_utils.TestDataContainer()
|
|
||||||
node_1 = node.Node(
|
|
||||||
node.NodeManager(None),
|
|
||||||
{'id': '1',
|
|
||||||
'uuid': 'aa-11',
|
|
||||||
'instance_uuid': 'aa',
|
|
||||||
'driver': 'pxe_ipmitool',
|
|
||||||
'driver_info': {
|
|
||||||
'ipmi_address': '1.1.1.1',
|
|
||||||
'ipmi_username': 'admin',
|
|
||||||
'ipmi_password': 'password',
|
|
||||||
'ip_address': '1.2.2.2'
|
|
||||||
},
|
|
||||||
'properties': {
|
|
||||||
'cpu': '8',
|
|
||||||
'ram': '16',
|
|
||||||
'local_disk': '10',
|
|
||||||
},
|
|
||||||
'power_state': 'on',
|
|
||||||
})
|
|
||||||
node_2 = node.Node(
|
|
||||||
node.NodeManager(None),
|
|
||||||
{'id': '2',
|
|
||||||
'uuid': 'bb-22',
|
|
||||||
'instance_uuid': 'bb',
|
|
||||||
'driver': 'pxe_ipmitool',
|
|
||||||
'driver_info': {
|
|
||||||
'ipmi_address': '2.2.2.2',
|
|
||||||
'ipmi_username': 'admin',
|
|
||||||
'ipmi_password': 'password',
|
|
||||||
'ip_address': '1.2.2.3'
|
|
||||||
},
|
|
||||||
'properties': {
|
|
||||||
'cpu': '16',
|
|
||||||
'ram': '32',
|
|
||||||
'local_disk': '100',
|
|
||||||
},
|
|
||||||
'power_state': 'on',
|
|
||||||
})
|
|
||||||
node_3 = node.Node(
|
|
||||||
node.NodeManager(None),
|
|
||||||
{'id': '3',
|
|
||||||
'uuid': 'cc-33',
|
|
||||||
'instance_uuid': 'cc',
|
|
||||||
'driver': 'pxe_ipmitool',
|
|
||||||
'driver_info': {
|
|
||||||
'ipmi_address': '3.3.3.3',
|
|
||||||
'ipmi_username': 'admin',
|
|
||||||
'ipmi_password': 'password',
|
|
||||||
'ip_address': '1.2.2.4'
|
|
||||||
},
|
|
||||||
'properties': {
|
|
||||||
'cpu': '32',
|
|
||||||
'ram': '64',
|
|
||||||
'local_disk': '1',
|
|
||||||
},
|
|
||||||
'power_state': 'rebooting',
|
|
||||||
})
|
|
||||||
node_4 = node.Node(
|
|
||||||
node.NodeManager(None),
|
|
||||||
{'id': '4',
|
|
||||||
'uuid': 'cc-44',
|
|
||||||
'instance_uuid': 'cc',
|
|
||||||
'driver': 'pxe_ipmitool',
|
|
||||||
'driver_info': {
|
|
||||||
'ipmi_address': '4.4.4.4',
|
|
||||||
'ipmi_username': 'admin',
|
|
||||||
'ipmi_password': 'password',
|
|
||||||
'ip_address': '1.2.2.5'
|
|
||||||
},
|
|
||||||
'properties': {
|
|
||||||
'cpu': '8',
|
|
||||||
'ram': '16',
|
|
||||||
'local_disk': '10',
|
|
||||||
},
|
|
||||||
'power_state': 'on',
|
|
||||||
})
|
|
||||||
node_5 = node.Node(
|
|
||||||
node.NodeManager(None),
|
|
||||||
{'id': '5',
|
|
||||||
'uuid': 'dd-55',
|
|
||||||
'instance_uuid': 'dd',
|
|
||||||
'driver': 'pxe_ipmitool',
|
|
||||||
'driver_info': {
|
|
||||||
'ipmi_address': '5.5.5.5',
|
|
||||||
'ipmi_username': 'admin',
|
|
||||||
'ipmi_password': 'password',
|
|
||||||
'ip_address': '1.2.2.6'
|
|
||||||
},
|
|
||||||
'properties': {
|
|
||||||
'cpu': '8',
|
|
||||||
'ram': '16',
|
|
||||||
'local_disk': '10',
|
|
||||||
},
|
|
||||||
'power_state': 'error',
|
|
||||||
})
|
|
||||||
TEST.ironicclient_nodes.add(node_1, node_2, node_3, node_4, node_5)
|
|
||||||
|
|
||||||
# Ports
|
|
||||||
TEST.ironicclient_ports = test_data_utils.TestDataContainer()
|
|
||||||
port_1 = port.Port(
|
|
||||||
port.PortManager(None),
|
|
||||||
{'id': '1-port-id',
|
|
||||||
'type': 'port',
|
|
||||||
'address': 'aa:aa:aa:aa:aa:aa'})
|
|
||||||
port_2 = port.Port(
|
|
||||||
port.PortManager(None),
|
|
||||||
{'id': '2-port-id',
|
|
||||||
'type': 'port',
|
|
||||||
'address': 'bb:bb:bb:bb:bb:bb'})
|
|
||||||
port_3 = port.Port(
|
|
||||||
port.PortManager(None),
|
|
||||||
{'id': '3-port-id',
|
|
||||||
'type': 'port',
|
|
||||||
'address': 'cc:cc:cc:cc:cc:cc'})
|
|
||||||
port_4 = port.Port(
|
|
||||||
port.PortManager(None),
|
|
||||||
{'id': '4-port-id',
|
|
||||||
'type': 'port',
|
|
||||||
'address': 'dd:dd:dd:dd:dd:dd'})
|
|
||||||
TEST.ironicclient_ports.add(port_1, port_2, port_3, port_4)
|
|
1
tuskar_sat_ui/overrides/infrastructure/__init__.py
Normal file
1
tuskar_sat_ui/overrides/infrastructure/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
__author__ = 'jomara'
|
3
tuskar_sat_ui/overrides/infrastructure/node_views.py
Normal file
3
tuskar_sat_ui/overrides/infrastructure/node_views.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
from tuskar_ui.infrastructure.nodes import views as nodes_views
|
||||||
|
|
||||||
|
nodes_views.DetailView.template_name = 'tuskar_sat_ui/overrides/infrastructure/templates/nodes/details.html'
|
Binary file not shown.
Loading…
Reference in New Issue
Block a user