Ryan Brady 64eeb59c72 Add discovery on demand
If node introspection fails, there is no way to re-run the process
within the UI.  This patch adds a button to the maintenance tab
to allow a user to re-run the process.

Change-Id: I16645643de83f212e89f858a85589d425474c5cd
2015-08-14 10:20:48 -04:00

270 lines
9.0 KiB
Python

# -*- 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.
from django.core.urlresolvers import reverse
from django.utils.translation import ugettext_lazy as _
from horizon import messages
from horizon import tables
from horizon.utils import memoized
from tuskar_ui import api
class DeleteNode(tables.BatchAction):
name = "delete"
action_present = _("Delete")
action_past = _("Deleting")
data_type_singular = _("Node")
data_type_plural = _("Nodes")
classes = ('btn-danger',)
def allowed(self, request, obj=None):
if not obj:
# this is necessary because table actions use this function
# with obj=None
return True
return (getattr(obj, 'instance_uuid', None) is None and
obj.power_state not in api.node.POWER_ON_STATES)
def action(self, request, obj_id):
if obj_id is None:
messages.error(request, _("Select some nodes to delete."))
return
api.node.Node.delete(request, obj_id)
class ActivateNode(tables.BatchAction):
name = "activate"
action_present = _("Activate")
action_past = _("Activated")
data_type_singular = _("Node")
data_type_plural = _("Nodes")
def allowed(self, request, obj=None):
if not obj:
# this is necessary because table actions use this function
# with obj=None
return True
return (obj.cpus and obj.memory_mb and obj.local_gb and
obj.cpu_arch)
def action(self, request, obj_id):
if obj_id is None:
messages.error(request, _("Select some nodes to activate."))
return
api.node.Node.set_maintenance(request, obj_id, False)
api.node.Node.set_power_state(request, obj_id, 'off')
class SetPowerStateOn(tables.BatchAction):
name = "set_power_state_on"
action_present = _("Power On")
action_past = _("Powering On")
data_type_singular = _("Node")
data_type_plural = _("Nodes")
def allowed(self, request, obj=None):
if not obj:
# this is necessary because table actions use this function
# with obj=None
return True
return obj.power_state not in api.node.POWER_ON_STATES
def action(self, request, obj_id):
if obj_id is None:
messages.error(request, _("Select some nodes to power on."))
return
api.node.Node.set_power_state(request, obj_id, 'on')
class SetPowerStateOff(tables.BatchAction):
name = "set_power_state_off"
action_present = _("Power Off")
action_past = _("Powering Off")
data_type_singular = _("Node")
data_type_plural = _("Nodes")
def allowed(self, request, obj=None):
if not obj:
# this is necessary because table actions use this function
# with obj=None
return True
return (
obj.power_state in api.node.POWER_ON_STATES and
getattr(obj, 'instance_uuid', None) is None
)
def action(self, request, obj_id):
if obj_id is None:
messages.error(request, _("Select some nodes to power off."))
return
api.node.Node.set_power_state(request, obj_id, 'off')
class NodeFilterAction(tables.FilterAction):
def filter(self, table, nodes, filter_string):
"""Really naive case-insensitive search."""
q = filter_string.lower()
def comp(node):
return any(q in unicode(value).lower() for value in (
node.ip_address,
node.cpus,
node.memory_mb,
node.local_gb,
))
return filter(comp, nodes)
class DiscoverNode(tables.BatchAction):
name = "discover_nodes"
action_present = _("Discover")
action_past = _("Discovered")
data_type_singular = _("Node")
data_type_plural = _("Nodes")
def allowed(self, request, obj=None):
if not obj:
# this is necessary because table actions use this function
# with obj=None
return True
return obj.state == api.node.MAINTENANCE_STATE
def action(self, request, obj_id):
if obj_id is None:
messages.error(request, _("Select some nodes to discover."))
return
api.node.Node.discover(request, [obj_id])
@memoized.memoized
def _get_role_link(role_id):
if role_id:
return reverse('horizon:infrastructure:roles:detail',
kwargs={'role_id': role_id})
def get_role_link(datum):
return _get_role_link(getattr(datum, 'role_id', None))
def get_power_state_with_transition(node):
if node.target_power_state and (
node.power_state != node.target_power_state):
return "{0} -> {1}".format(
node.power_state, node.target_power_state)
return node.power_state
def get_state_string(node):
state_dict = {
api.node.DISCOVERING_STATE: _('Discovering'),
api.node.DISCOVERED_STATE: _('Discovered'),
api.node.PROVISIONED_STATE: _('Provisioned'),
api.node.PROVISIONING_FAILED_STATE: _('Provisioning Failed'),
api.node.PROVISIONING_STATE: _('Provisioning'),
api.node.FREE_STATE: _('Free'),
}
node_state = node.state
return state_dict.get(node_state, node_state)
class BaseNodesTable(tables.DataTable):
node = tables.Column('uuid',
link="horizon:infrastructure:nodes:node_detail",
verbose_name=_("Node Name"))
role_name = tables.Column('role_name',
link=get_role_link,
verbose_name=_("Deployment Role"))
cpus = tables.Column('cpus',
verbose_name=_("CPU (cores)"))
memory_mb = tables.Column('memory_mb',
verbose_name=_("Memory (MB)"))
local_gb = tables.Column('local_gb',
verbose_name=_("Disk (GB)"))
power_status = tables.Column(get_power_state_with_transition,
verbose_name=_("Power Status"))
state = tables.Column(get_state_string,
verbose_name=_("Status"))
class Meta(object):
name = "nodes_table"
verbose_name = _("Nodes")
table_actions = (NodeFilterAction, SetPowerStateOn, SetPowerStateOff,
DeleteNode)
row_actions = (SetPowerStateOn, SetPowerStateOff, DeleteNode)
template = "horizon/common/_enhanced_data_table.html"
def get_object_id(self, datum):
return datum.uuid
def get_object_display(self, datum):
return datum.uuid
class AllNodesTable(BaseNodesTable):
class Meta(object):
name = "all_nodes_table"
verbose_name = _("All")
hidden_title = False
columns = ('node', 'cpus', 'memory_mb', 'local_gb', 'power_status',
'state')
table_actions = (NodeFilterAction, SetPowerStateOn, SetPowerStateOff,
DeleteNode)
row_actions = (SetPowerStateOn, SetPowerStateOff, DeleteNode)
template = "horizon/common/_enhanced_data_table.html"
class ProvisionedNodesTable(BaseNodesTable):
class Meta(object):
name = "provisioned_nodes_table"
verbose_name = _("Provisioned")
hidden_title = False
table_actions = (NodeFilterAction, SetPowerStateOn, SetPowerStateOff,
DeleteNode)
row_actions = (SetPowerStateOn, SetPowerStateOff, DeleteNode)
template = "horizon/common/_enhanced_data_table.html"
class FreeNodesTable(BaseNodesTable):
class Meta(object):
name = "free_nodes_table"
verbose_name = _("Free")
hidden_title = False
columns = ('node', 'cpus', 'memory_mb', 'local_gb', 'power_status')
table_actions = (NodeFilterAction, SetPowerStateOn, SetPowerStateOff,
DeleteNode)
row_actions = (SetPowerStateOn, SetPowerStateOff, DeleteNode,)
template = "horizon/common/_enhanced_data_table.html"
class MaintenanceNodesTable(BaseNodesTable):
class Meta(object):
name = "maintenance_nodes_table"
verbose_name = _("Maintenance")
hidden_title = False
columns = ('node', 'cpus', 'memory_mb', 'local_gb', 'power_status',
'state')
table_actions = (NodeFilterAction, ActivateNode, SetPowerStateOn,
SetPowerStateOff, DiscoverNode, DeleteNode)
row_actions = (ActivateNode, SetPowerStateOn, SetPowerStateOff,
DeleteNode)
template = "horizon/common/_enhanced_data_table.html"