summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--openstack_dashboard/api/nova.py2
-rw-r--r--openstack_dashboard/api/tuskar.py39
-rw-r--r--openstack_dashboard/dashboards/infrastructure/fixtures/initial_data.json6
-rw-r--r--openstack_dashboard/dashboards/infrastructure/models.py2
-rw-r--r--openstack_dashboard/dashboards/infrastructure/resource_management/nodes/tables.py4
-rw-r--r--openstack_dashboard/dashboards/infrastructure/resource_management/racks/views.py5
-rw-r--r--openstack_dashboard/dashboards/infrastructure/resource_management/racks/workflows.py81
-rw-r--r--openstack_dashboard/local/local_settings.py.example8
8 files changed, 107 insertions, 40 deletions
diff --git a/openstack_dashboard/api/nova.py b/openstack_dashboard/api/nova.py
index ba42c9b0..35535183 100644
--- a/openstack_dashboard/api/nova.py
+++ b/openstack_dashboard/api/nova.py
@@ -30,8 +30,10 @@ from django.utils.translation import ugettext_lazy as _
from novaclient.v1_1 import client as nova_client
from novaclient.v1_1.contrib.list_extensions import ListExtManager
from novaclient.v1_1 import security_group_rules as nova_rules
+from novaclient.v1_1.contrib import baremetal
from novaclient.v1_1.security_groups import SecurityGroup as NovaSecurityGroup
from novaclient.v1_1.servers import REBOOT_HARD
+from novaclient.v1_1.servers import REBOOT_SOFT
from horizon.conf import HORIZON_CONFIG
from horizon.utils.memoized import memoized
diff --git a/openstack_dashboard/api/tuskar.py b/openstack_dashboard/api/tuskar.py
index 2ebdeb45..46841017 100644
--- a/openstack_dashboard/api/tuskar.py
+++ b/openstack_dashboard/api/tuskar.py
@@ -27,12 +27,13 @@ from horizon import exceptions
from tuskarclient.v1 import client as tuskar_client
-from openstack_dashboard.api import base
+from openstack_dashboard.api import base, nova
import openstack_dashboard.dashboards.infrastructure.models as dummymodels
LOG = logging.getLogger(__name__)
TUSKAR_ENDPOINT_URL = getattr(settings, 'TUSKAR_ENDPOINT_URL')
+NOVA_BAREMETAL_CREDS = getattr(settings, 'NOVA_BAREMETAL_CREDS')
# FIXME: request isn't used right in the tuskar client right now, but looking
@@ -137,11 +138,26 @@ class Node(StringIdAPIResourceWrapper):
"""Wrapper for the Node object returned by the
dummy model.
"""
- _attrs = ['name', 'mac_address', 'ip_address', 'status', 'usage', 'rack']
+ _attrs = ['id', 'pm_address', 'cpus', 'memory_mb', 'service_host',
+ 'local_gb']
+
+ @classmethod
+ def manager(cls):
+ nc = nova.nova_client.Client(
+ NOVA_BAREMETAL_CREDS['user'],
+ NOVA_BAREMETAL_CREDS['password'],
+ NOVA_BAREMETAL_CREDS['tenant'],
+ auth_url=NOVA_BAREMETAL_CREDS['auth_url'],
+ bypass_url=NOVA_BAREMETAL_CREDS['bypass_url'])
+ return nova.baremetal.BareMetalNodeManager(nc)
@classmethod
def get(cls, request, node_id):
- return cls(dummymodels.Node.objects.get(id=node_id))
+ return cls(cls.manager().get(node_id))
+
+ @classmethod
+ def list(cls, request):
+ return cls.manager().list()
@classmethod
def list_unracked(cls, request):
@@ -292,9 +308,16 @@ class Node(StringIdAPIResourceWrapper):
self._alerts = [Alert(a) for a in
dummymodels.Alert.objects
.filter(object_type='node')
- .filter(object_id=int(self.id))]
+ .filter(object_id=str(self.id))]
return self._alerts
+ @property
+ def mac_address(self):
+ try:
+ return self._apiresource.interfaces[0]['address']
+ except:
+ return None
+
class Rack(StringIdAPIResourceWrapper):
"""Wrapper for the Rack object returned by the
@@ -364,10 +387,10 @@ class Rack(StringIdAPIResourceWrapper):
## fetch nodes from nova baremetal
@property
def list_nodes(self):
- return []
- #if not hasattr(self, '_nodes'):
- # self._nodes = [Node(h) for h in self._apiresource.node_set.all()]
- #return self._nodes
+ if not hasattr(self, '_nodes'):
+ self._nodes = [Node.get(None, node['id']) for node in (
+ self._apiresource.nodes)]
+ return self._nodes
def nodes_count(self):
return len(self._apiresource.nodes)
diff --git a/openstack_dashboard/dashboards/infrastructure/fixtures/initial_data.json b/openstack_dashboard/dashboards/infrastructure/fixtures/initial_data.json
index 5cbd8e2c..281af6e4 100644
--- a/openstack_dashboard/dashboards/infrastructure/fixtures/initial_data.json
+++ b/openstack_dashboard/dashboards/infrastructure/fixtures/initial_data.json
@@ -88,7 +88,7 @@
{"pk": 53, "model": "infrastructure.capacity", "fields": {"value": 160, "unit": "GB", "object_id": 7, "content_type": ["infrastructure", "flavortemplate"], "name": "storage"}},
{"pk": 54, "model": "infrastructure.capacity", "fields": {"value": 0, "unit": "GB", "object_id": 7, "content_type": ["infrastructure", "flavortemplate"], "name": "ephemeral_disk"}},
{"pk": 55, "model": "infrastructure.capacity", "fields": {"value": 0, "unit": "MB", "object_id": 7, "content_type": ["infrastructure", "flavortemplate"], "name": "swap_disk"}},
- {"pk": 1, "model": "infrastructure.alert", "fields": {"message": "Switch is not accessible.", "object_id": 1, "object_type": "rack", "time": "2011-09-01T13:20:30+03:00"}},
- {"pk": 2, "model": "infrastructure.alert", "fields": {"message": "Nova service is not running.", "object_id": 1, "object_type": "node", "time": "2011-09-01T13:20:30+03:00"}},
- {"pk": 3, "model": "infrastructure.alert", "fields": {"message": "Disk usage is over 90%.", "object_id": 1, "object_type": "node", "time": "2011-09-01T13:20:30+03:00"}}
+ {"pk": 1, "model": "infrastructure.alert", "fields": {"message": "Switch is not accessible.", "object_id": "1", "object_type": "rack", "time": "2011-09-01T13:20:30+03:00"}},
+ {"pk": 2, "model": "infrastructure.alert", "fields": {"message": "Nova service is not running.", "object_id": "1", "object_type": "node", "time": "2011-09-01T13:20:30+03:00"}},
+ {"pk": 3, "model": "infrastructure.alert", "fields": {"message": "Disk usage is over 90%.", "object_id": "1", "object_type": "node", "time": "2011-09-01T13:20:30+03:00"}}
]
diff --git a/openstack_dashboard/dashboards/infrastructure/models.py b/openstack_dashboard/dashboards/infrastructure/models.py
index 513e463d..8097e5b1 100644
--- a/openstack_dashboard/dashboards/infrastructure/models.py
+++ b/openstack_dashboard/dashboards/infrastructure/models.py
@@ -34,7 +34,7 @@ class Alert(models.Model):
class Meta:
db_table = 'infrastructure_alerts'
- object_id = models.PositiveIntegerField()
+ object_id = models.CharField(max_length=50)
object_type = models.CharField(max_length=20)
message = models.CharField(max_length=250)
time = models.DateTimeField()
diff --git a/openstack_dashboard/dashboards/infrastructure/resource_management/nodes/tables.py b/openstack_dashboard/dashboards/infrastructure/resource_management/nodes/tables.py
index 0b54922d..f1b19783 100644
--- a/openstack_dashboard/dashboards/infrastructure/resource_management/nodes/tables.py
+++ b/openstack_dashboard/dashboards/infrastructure/resource_management/nodes/tables.py
@@ -39,12 +39,12 @@ class NodesTable(tables.DataTable):
("active", True),
("error", False),
)
- name = tables.Column("name",
+ service_host = tables.Column("service_host",
link=("horizon:infrastructure:"
"resource_management:nodes:detail"),
verbose_name=_("Name"))
mac_address = tables.Column("mac_address", verbose_name=_("MAC Address"))
- ip_address = tables.Column("ip_address", verbose_name=_("IP Address"))
+ pm_address = tables.Column("pm_address", verbose_name=_("IP Address"))
status = tables.Column("status",
verbose_name=_("Status"),
status=True,
diff --git a/openstack_dashboard/dashboards/infrastructure/resource_management/racks/views.py b/openstack_dashboard/dashboards/infrastructure/resource_management/racks/views.py
index 2ab8bf82..b3bf1872 100644
--- a/openstack_dashboard/dashboards/infrastructure/resource_management/racks/views.py
+++ b/openstack_dashboard/dashboards/infrastructure/resource_management/racks/views.py
@@ -67,11 +67,10 @@ class EditView(workflows.WorkflowView):
def get_initial(self):
obj = api.tuskar.Rack.get(self.request, self.kwargs['rack_id'])
- mac_str = "\n".join([x.mac_address for x in obj.list_nodes])
+ # mac_str = "\n".join([x.mac_address for x in obj.list_nodes])
return {'name': obj.name, 'resource_class_id': obj.resource_class_id,
'location': obj.location, 'subnet': obj.subnet,
- 'state': obj.state, 'node_macs': mac_str,
- 'rack_id': self.kwargs['rack_id']}
+ 'state': obj.state, 'rack_id': self.kwargs['rack_id']}
class DetailEditView(EditView):
diff --git a/openstack_dashboard/dashboards/infrastructure/resource_management/racks/workflows.py b/openstack_dashboard/dashboards/infrastructure/resource_management/racks/workflows.py
index d415ee0d..0499dc86 100644
--- a/openstack_dashboard/dashboards/infrastructure/resource_management/racks/workflows.py
+++ b/openstack_dashboard/dashboards/infrastructure/resource_management/racks/workflows.py
@@ -26,28 +26,52 @@ import re
class NodeCreateAction(workflows.Action):
- node_macs = forms.CharField(label=_("MAC Addresses"),
- widget=forms.Textarea(attrs={'rows': 12, 'cols': 20}),
- required=False)
+ # node_macs = forms.CharField(label=_("MAC Addresses"),
+ # widget=forms.Textarea(attrs={'rows': 12, 'cols': 20}),
+ # required=False)
+
+ node_name = forms.CharField(label="Name", required=True)
+ prov_mac_address = forms.CharField(label=("MAC Address"),
+ required=True)
+
+ # Hardware Specifications
+ cpus = forms.CharField(label="CPUs", required=True)
+ memory_mb = forms.CharField(label="Memory", required=True)
+ local_gb = forms.CharField(label="Local Disk (GB)", required=True)
+
+ # Power Management
+ pm_address = forms.CharField(label="IP Address", required=True)
+ pm_user = forms.CharField(label="User", required=True)
+ pm_password = forms.CharField(label="Password",
+ required=True,
+ widget=forms.PasswordInput(
+ render_value=False))
+
+ # Access
+ terminal_port = forms.CharField(label="Terminal Port", required=False)
class Meta:
name = _("Nodes")
-# mawagner FIXME - We presently disable this box, but leave the form.
-# We need to decide if this should be supported, or whether users should
-# be required to use the table view (to be implemented).
-# NOTE: The form input is disabled, but the input is also ignored
-# even if it were present.
-class NodeEditAction(workflows.Action):
- node_macs = forms.CharField(label=_("MAC Addresses"),
- widget=forms.Textarea(attrs={'rows': 12, 'cols': 20,
- 'readonly': 'readonly'}),
- required=False)
+# mawagner FIXME - For the demo, all we can really do is edit the one
+# associated node. That's very much _not_ what this form is actually
+# about, though.
+class NodeEditAction(NodeCreateAction):
class Meta:
name = _("Nodes")
+ # FIXME: mawagner - This is all for debugging. The idea is to fetch
+ # the first node and display it in the form; the latter part needs
+ # implementation. This also needs error handling; right now for testing
+ # I want to let it fail, but don't commit like that! :)
+ def __init__(self, request, *args, **kwargs):
+ super(NodeEditAction, self).__init__(request, *args, **kwargs)
+ rack_id = self.initial['rack_id']
+ rack = api.tuskar.Rack.get(request, rack_id)
+ nodes = rack.list_nodes
+
class RackCreateInfoAction(workflows.Action):
name = forms.RegexField(label=_("Name"),
@@ -121,17 +145,19 @@ class EditRackInfo(CreateRackInfo):
class CreateNodes(workflows.Step):
action_class = NodeCreateAction
- contributes = ('node_macs',)
+ contributes = ('node_name', 'prov_mac_address', 'cpus', 'memory_mb',
+ 'local_gb', 'pm_address', 'pm_user', 'pm_password',
+ 'terminal_port')
def get_nodes_data():
pass
-class EditNodes(workflows.Step):
+class EditNodes(CreateNodes):
action_class = NodeEditAction
depends_on = ('rack_id',)
contributes = ('node_macs',)
- help_text = _("Editing nodes via textbox is not presently supported.")
+ # help_text = _("Editing nodes via textbox is not presently supported.")
class CreateRack(workflows.Workflow):
@@ -144,17 +170,28 @@ class CreateRack(workflows.Workflow):
def handle(self, request, data):
try:
+ if data['node_name'] is not None:
+ node = api
+ node = api.tuskar.Node.manager().create(data['node_name'],
+ data['cpus'], data['memory_mb'],
+ data['local_gb'], data['prov_mac_address'],
+ data['pm_address'], data['pm_user'],
+ data['pm_password'], data['terminal_port'])
+
+ if node:
+ node_id = node.id
+ else:
+ node_id = None
+
+ # Then, register the Rack, including the node if it exists
rack = api.tuskar.Rack.create(request, data['name'],
data['resource_class_id'],
data['location'],
- data['subnet'])
-
- if data['node_macs'] is not None:
- nodes = data['node_macs'].splitlines(False)
- api.tuskar.Rack.register_nodes(rack, nodes)
+ data['subnet'],
+ [{'id': node_id}])
return True
- except:
+ except Exception as ex:
exceptions.handle(request, _("Unable to create rack."))
diff --git a/openstack_dashboard/local/local_settings.py.example b/openstack_dashboard/local/local_settings.py.example
index f0a2f142..821304cd 100644
--- a/openstack_dashboard/local/local_settings.py.example
+++ b/openstack_dashboard/local/local_settings.py.example
@@ -355,4 +355,10 @@ SECURITY_GROUP_RULES = {
# FIXME: this will eventually be unneeded, as it will be retrieved from Keystone
#TUSKAR_ENDPOINT_URL = "http://127.0.0.1:6385"
-
+#NOVA_BAREMETAL_CREDS = {
+# 'user': 'admin',
+# 'password': 'admin_password_here',
+# 'tenant': 'admin',
+# 'auth_url': 'http://localhost:5001/v2.0/',
+# 'bypass_url': 'http://localhost:9774/v2/692567cd99f84f5d8f26ec23ff0ba460'
+#}