Adjust Horizon plugin to register external functionality with a legit way of deployment
This commit is contained in:
parent
1767b1eb51
commit
9efdd2b4cf
@ -1,39 +1,6 @@
|
||||
# OnRack plugin for OpenStack Horizon dashboard
|
||||
|
||||
On Shovel system:
|
||||
|
||||
- Set monorail:httpHost, ironic:httpHost and keystone:httpHost found in ./shovel/config.json
|
||||
|
||||
- Start shovel services:
|
||||
|
||||
cd ./shovel ; nodejs index.js
|
||||
|
||||
- On Horizon system:
|
||||
|
||||
Set SHOVEL_URL in ./horizon-shovel/openstack_dashboard/dashboards/admin/hypervisors/baremetal/shovel.py
|
||||
|
||||
Copy horizon-shovel contents to horizon:
|
||||
|
||||
cp ./horizon-shovel/* /opt/stack/horizon
|
||||
|
||||
- Restart Apache:
|
||||
|
||||
sudo service apache2 restart
|
||||
|
||||
- Enable OnRack event tasker:
|
||||
|
||||
Install Celery:
|
||||
|
||||
sudo pip install celery
|
||||
|
||||
Start celery beat service:
|
||||
|
||||
cd /opt/stack/horizon/ ; python manage.py celery worker -B -E
|
||||
|
||||
- Connect to Horizon dashboard URL and login
|
||||
|
||||
- Navigate to Admin -> System -> Hypervisors page
|
||||
|
||||
- Click on 'Bare Metal' tab
|
||||
|
||||
|
||||
git clone https://github.com/keedya/Shovel-horizon.git
|
||||
cd Shovel-horizon/Horizon
|
||||
sudo ./install.sh --url <Shovel IP> --location <Horizon Path>
|
||||
sudo service apache2 restart
|
||||
|
33
Horizon/install.sh
Executable file
33
Horizon/install.sh
Executable file
@ -0,0 +1,33 @@
|
||||
#!/bin/bash
|
||||
|
||||
TEMP=`getopt -o u:l: --long url: --long location: -- "$@"`
|
||||
|
||||
if [ $? != 0 ] ; then echo "Exit" ; exit 1 ; fi
|
||||
|
||||
eval set -- "$TEMP"
|
||||
echo $TEMP
|
||||
ADDR_IP=${ADDR_IP-}
|
||||
FILE_LOC=${FILE_LOC-}
|
||||
|
||||
while true ; do
|
||||
case "$1" in
|
||||
-u | --url) ADDR_IP=$2 ;shift 2 ;;
|
||||
-l | --location) FILE_LOC=$2;shift 2 ;;
|
||||
--) shift; break ;;
|
||||
*) echo "Internal error!" ; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
echo "get shovel url: " $ADDR_IP
|
||||
echo "get file location: " $FILE_LOC
|
||||
if [ -z "$ADDR_IP" -o -z "$FILE_LOC" ]
|
||||
then
|
||||
echo "You must specify ipaddr of shovel and horizon location"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#replace in shovel.py SHOVEL_URL with the new addre value
|
||||
sed -i "s|.*URI = .*|URI = \"$ADDR_IP\" + SHOVEL_BASE_API|g" rackhd/shovel.py
|
||||
#copy rackhd to horizon admin dashboard
|
||||
cp -r rackhd $FILE_LOC/openstack_dashboard/dashboards/admin
|
||||
#copy _50_admin_rackhd_panels.py to dashboard enabled
|
||||
cp _50_admin_rackhd_panels.py $FILE_LOC/openstack_dashboard/enabled
|
@ -1,72 +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
|
||||
import json
|
||||
import requests
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from horizon import exceptions
|
||||
from horizon import tabs
|
||||
|
||||
import openstack_dashboard.api
|
||||
from openstack_dashboard.dashboards.admin.hypervisors.baremetal import tables
|
||||
from openstack_dashboard.dashboards.admin.hypervisors.baremetal import shovel
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
class OnRackTab(tabs.TableTab):
|
||||
table_classes = (tables.BareMetalTable,)
|
||||
name = _("Bare Metal")
|
||||
slug = "baremetal"
|
||||
template_name = "horizon/common/_data_table.html"
|
||||
|
||||
class NodeData:
|
||||
def __init__(self, uuid, name, hwaddr, events, state):
|
||||
self.id = uuid
|
||||
self.name = name
|
||||
self.uuid = uuid
|
||||
self.hwaddr = hwaddr
|
||||
self.events = events
|
||||
self.state = state
|
||||
|
||||
def _find_ironic_node(self, id):
|
||||
# ISSUE: iterating all nodes because query by name (onrack id) isn't working in ironic?
|
||||
nodes = shovel.get_ironic_nodes()
|
||||
for n in nodes['nodes']:
|
||||
if n['extra'].get('nodeid', None) == id:
|
||||
return n
|
||||
return None
|
||||
|
||||
def get_baremetal_data(self):
|
||||
data = []
|
||||
try:
|
||||
nodes = shovel.request_nodes_get()
|
||||
for n in nodes:
|
||||
if n['type'] in {'enclosure','switch'}:
|
||||
continue
|
||||
dmi = shovel.get_catalog_data_by_source(n['id'],'dmi')
|
||||
name = dmi['System Information']['Product Name']
|
||||
hwaddr = n['name']
|
||||
id = n['id']
|
||||
events = '0'
|
||||
n = self._find_ironic_node(id)
|
||||
if n is not None:
|
||||
events = n['extra'].get('eventcnt','0')
|
||||
state = 'Registered'
|
||||
else:
|
||||
state = 'Unregistered'
|
||||
data.append(self.NodeData(id, name, hwaddr, events, state))
|
||||
return data
|
||||
except Exception, e:
|
||||
LOG.error("Excepton in get_baremetal_data(): {0}".format(e))
|
||||
return data
|
@ -1,46 +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 django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from horizon import exceptions
|
||||
from horizon import tabs
|
||||
|
||||
from openstack_dashboard.api import nova
|
||||
from openstack_dashboard.dashboards.admin.hypervisors.compute \
|
||||
import tabs as cmp_tabs
|
||||
from openstack_dashboard.dashboards.admin.hypervisors.baremetal \
|
||||
import tabs as baremetal_tabs
|
||||
from openstack_dashboard.dashboards.admin.hypervisors import tables
|
||||
|
||||
|
||||
class HypervisorTab(tabs.TableTab):
|
||||
table_classes = (tables.AdminHypervisorsTable,)
|
||||
name = _("Hypervisor")
|
||||
slug = "hypervisor"
|
||||
template_name = "horizon/common/_detail_table.html"
|
||||
|
||||
def get_hypervisors_data(self):
|
||||
hypervisors = []
|
||||
try:
|
||||
hypervisors = nova.hypervisor_list(self.request)
|
||||
except Exception:
|
||||
exceptions.handle(self.request,
|
||||
_('Unable to retrieve hypervisor information.'))
|
||||
|
||||
return hypervisors
|
||||
|
||||
|
||||
class HypervisorHostTabs(tabs.TabGroup):
|
||||
slug = "hypervisor_info"
|
||||
tabs = (HypervisorTab, cmp_tabs.ComputeHostTab, baremetal_tabs.OnRackTab)
|
||||
sticky = True
|
@ -1,35 +0,0 @@
|
||||
# Copyright 2013 B1 Systems GmbH
|
||||
#
|
||||
# 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.conf.urls import include
|
||||
from django.conf.urls import patterns
|
||||
from django.conf.urls import url
|
||||
|
||||
from openstack_dashboard.dashboards.admin.hypervisors.compute \
|
||||
import urls as compute_urls
|
||||
from openstack_dashboard.dashboards.admin.hypervisors.baremetal \
|
||||
import urls as baremetal_urls
|
||||
|
||||
from openstack_dashboard.dashboards.admin.hypervisors import views
|
||||
|
||||
|
||||
urlpatterns = patterns(
|
||||
'openstack_dashboard.dashboards.admin.hypervisors.views',
|
||||
url(r'^(?P<hypervisor>[^/]+)/$',
|
||||
views.AdminDetailView.as_view(),
|
||||
name='detail'),
|
||||
url(r'^$', views.AdminIndexView.as_view(), name='index'),
|
||||
url(r'', include(compute_urls, namespace='compute')),
|
||||
url(r'', include(baremetal_urls, namespace='baremetal')),
|
||||
)
|
@ -1,91 +0,0 @@
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from openstack_dashboard.dashboards.admin.hypervisors.baremetal import shovel
|
||||
from openstack_dashboard.api import nova
|
||||
from horizon import exceptions
|
||||
from horizon import messages
|
||||
|
||||
from celery.decorators import task
|
||||
from datetime import timedelta
|
||||
|
||||
import re
|
||||
import logging
|
||||
import json
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
def log_sel_all(sel):
|
||||
""" Simple SEL logger """
|
||||
for entry in sel:
|
||||
LOG.info(
|
||||
'logId: {0}\n'
|
||||
'sensorType: {1}\n'
|
||||
'sensorNumber: {2}\n'
|
||||
'event: {3}\n'
|
||||
'asserted: {4}\n'
|
||||
.format(entry['logId'],
|
||||
entry['sensorType'],
|
||||
entry['sensorNumber'],
|
||||
entry['event'],
|
||||
entry['value']))
|
||||
return True
|
||||
|
||||
|
||||
def log_sel_entry(entry):
|
||||
""" Simple SEL entry logger """
|
||||
LOG.info(
|
||||
'logId: {0}\n'
|
||||
'sensorType: {1}\n'
|
||||
'sensorNumber: {2}\n'
|
||||
'event: {3}\n'
|
||||
'asserted: {4}\n'
|
||||
.format(entry['logId'],
|
||||
entry['sensorType'],
|
||||
entry['sensorNumber'],
|
||||
entry['event'],
|
||||
entry['value']))
|
||||
return True
|
||||
|
||||
|
||||
def find_sel_entry_re(sel, regex):
|
||||
""" Return a list of searched regex expressions in each SEL entry """
|
||||
entry_list = []
|
||||
for entry in sel:
|
||||
if regex and regex.strip():
|
||||
match = re.search(r""+regex+"", json.dumps(entry, ensure_ascii=True))
|
||||
if match:
|
||||
entry_list.append(entry)
|
||||
return entry_list
|
||||
|
||||
|
||||
def update_events(events, ecount, entry_list, uuid):
|
||||
""" Update the ironic nodes extra metadata with new event match """
|
||||
for entry in entry_list:
|
||||
# update the latest event
|
||||
if int(entry['time']) > int(events['time']):
|
||||
LOG.info('update_event(): updating event for node {0} time:{1}'.format(uuid,entry['time']))
|
||||
ecount += 1
|
||||
p = json.loads( '[ {"path": "/extra/events", "value": ' + json.dumps(entry, ensure_ascii=True) + ', "op": "replace"}, {"path": "/extra/eventcnt", "value": ' + str(ecount) + ', "op": "replace"} ]' )
|
||||
shovel.node_patch(uuid, p)
|
||||
return True
|
||||
|
||||
|
||||
@task()
|
||||
def SELPoller():
|
||||
""" Periodic task to poll for monorail SEL events """
|
||||
nodes = shovel.get_ironic_nodes()
|
||||
for n in nodes['nodes']:
|
||||
extra = n['extra']
|
||||
nodeid = extra.get('nodeid', None)
|
||||
name = extra.get('name', None)
|
||||
events = extra.get('events', None)
|
||||
ecount = int(extra.get('eventcnt', 0))
|
||||
if nodeid is not None:
|
||||
failnode = extra.get('failover', None)
|
||||
regex = extra.get('eventre', None)
|
||||
if regex is not None:
|
||||
sel = shovel.get_current_sel_data(nodeid)[0].get('sel', None)
|
||||
if sel is not None:
|
||||
update_events(events, ecount, find_sel_entry_re(sel, regex), n['uuid'])
|
||||
return True
|
||||
|
||||
|
@ -1,355 +0,0 @@
|
||||
# Copyright 2012 United States Government as represented by the
|
||||
# Administrator of the National Aeronautics and Space Administration.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Copyright 2012 Nebula, Inc.
|
||||
#
|
||||
# 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
|
||||
import os
|
||||
import sys
|
||||
import warnings
|
||||
|
||||
import django
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from openstack_dashboard import exceptions
|
||||
from openstack_dashboard.static_settings import get_staticfiles_dirs # noqa
|
||||
|
||||
import djcelery
|
||||
from datetime import timedelta
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
'NAME': '/opt/stack/horizon/openstack_dashboard/static/db/horizon.db',
|
||||
}
|
||||
}
|
||||
|
||||
CELERYBEAT_SCHEDULE = {
|
||||
"runs-every-5-seconds": {
|
||||
"task": "openstack_dashboard.dashboards.admin.tasks.SELPoller",
|
||||
"schedule": timedelta(seconds=5)
|
||||
},
|
||||
}
|
||||
CELERY_ALWAYS_EAGER = False
|
||||
CELERYBEAT_SCHEDULER = "djcelery.schedulers.DatabaseScheduler"
|
||||
djcelery.setup_loader()
|
||||
|
||||
warnings.formatwarning = lambda message, category, *args, **kwargs: \
|
||||
'%s: %s' % (category.__name__, message)
|
||||
|
||||
ROOT_PATH = os.path.dirname(os.path.abspath(__file__))
|
||||
BIN_DIR = os.path.abspath(os.path.join(ROOT_PATH, '..', 'bin'))
|
||||
|
||||
if ROOT_PATH not in sys.path:
|
||||
sys.path.append(ROOT_PATH)
|
||||
|
||||
DEBUG = False
|
||||
TEMPLATE_DEBUG = DEBUG
|
||||
|
||||
SITE_BRANDING = 'OpenStack Dashboard'
|
||||
|
||||
WEBROOT = '/'
|
||||
LOGIN_URL = None
|
||||
LOGOUT_URL = None
|
||||
LOGIN_REDIRECT_URL = None
|
||||
|
||||
|
||||
ROOT_URLCONF = 'openstack_dashboard.urls'
|
||||
|
||||
HORIZON_CONFIG = {
|
||||
'user_home': 'openstack_dashboard.views.get_user_home',
|
||||
'ajax_queue_limit': 10,
|
||||
'auto_fade_alerts': {
|
||||
'delay': 3000,
|
||||
'fade_duration': 1500,
|
||||
'types': ['alert-success', 'alert-info']
|
||||
},
|
||||
'help_url': "http://docs.openstack.org",
|
||||
'exceptions': {'recoverable': exceptions.RECOVERABLE,
|
||||
'not_found': exceptions.NOT_FOUND,
|
||||
'unauthorized': exceptions.UNAUTHORIZED},
|
||||
'angular_modules': [],
|
||||
'js_files': [],
|
||||
'js_spec_files': [],
|
||||
}
|
||||
|
||||
# Set to True to allow users to upload images to glance via Horizon server.
|
||||
# When enabled, a file form field will appear on the create image form.
|
||||
# See documentation for deployment considerations.
|
||||
HORIZON_IMAGES_ALLOW_UPLOAD = True
|
||||
|
||||
# The OPENSTACK_IMAGE_BACKEND settings can be used to customize features
|
||||
# in the OpenStack Dashboard related to the Image service, such as the list
|
||||
# of supported image formats.
|
||||
OPENSTACK_IMAGE_BACKEND = {
|
||||
'image_formats': [
|
||||
('', _('Select format')),
|
||||
('aki', _('AKI - Amazon Kernel Image')),
|
||||
('ami', _('AMI - Amazon Machine Image')),
|
||||
('ari', _('ARI - Amazon Ramdisk Image')),
|
||||
('docker', _('Docker')),
|
||||
('iso', _('ISO - Optical Disk Image')),
|
||||
('ova', _('OVA - Open Virtual Appliance')),
|
||||
('qcow2', _('QCOW2 - QEMU Emulator')),
|
||||
('raw', _('Raw')),
|
||||
('vdi', _('VDI - Virtual Disk Image')),
|
||||
('vhd', _('VHD - Virtual Hard Disk')),
|
||||
('vmdk', _('VMDK - Virtual Machine Disk')),
|
||||
]
|
||||
}
|
||||
|
||||
MIDDLEWARE_CLASSES = (
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
)
|
||||
if django.VERSION >= (1, 8, 0):
|
||||
MIDDLEWARE_CLASSES += (
|
||||
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',)
|
||||
else:
|
||||
MIDDLEWARE_CLASSES += ('django.middleware.doc.XViewMiddleware',)
|
||||
MIDDLEWARE_CLASSES += (
|
||||
'horizon.middleware.HorizonMiddleware',
|
||||
'django.middleware.locale.LocaleMiddleware',
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
)
|
||||
|
||||
TEMPLATE_CONTEXT_PROCESSORS = (
|
||||
'django.core.context_processors.debug',
|
||||
'django.core.context_processors.i18n',
|
||||
'django.core.context_processors.request',
|
||||
'django.core.context_processors.media',
|
||||
'django.core.context_processors.static',
|
||||
'django.contrib.messages.context_processors.messages',
|
||||
'horizon.context_processors.horizon',
|
||||
'openstack_dashboard.context_processors.openstack',
|
||||
)
|
||||
|
||||
TEMPLATE_LOADERS = (
|
||||
'django.template.loaders.filesystem.Loader',
|
||||
'django.template.loaders.app_directories.Loader',
|
||||
'horizon.loaders.TemplateLoader',
|
||||
)
|
||||
|
||||
TEMPLATE_DIRS = (
|
||||
os.path.join(ROOT_PATH, 'templates'),
|
||||
)
|
||||
|
||||
STATICFILES_FINDERS = (
|
||||
'django.contrib.staticfiles.finders.FileSystemFinder',
|
||||
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
|
||||
'compressor.finders.CompressorFinder',
|
||||
)
|
||||
|
||||
COMPRESS_PRECOMPILERS = (
|
||||
('text/scss', 'django_pyscss.compressor.DjangoScssFilter'),
|
||||
)
|
||||
|
||||
COMPRESS_CSS_FILTERS = (
|
||||
'compressor.filters.css_default.CssAbsoluteFilter',
|
||||
)
|
||||
|
||||
COMPRESS_ENABLED = True
|
||||
COMPRESS_OUTPUT_DIR = 'dashboard'
|
||||
COMPRESS_CSS_HASHING_METHOD = 'hash'
|
||||
COMPRESS_PARSER = 'compressor.parser.HtmlParser'
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'openstack_dashboard',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'django.contrib.humanize',
|
||||
'django_pyscss',
|
||||
'openstack_dashboard.django_pyscss_fix',
|
||||
'compressor',
|
||||
'horizon',
|
||||
'openstack_auth',
|
||||
'periodically',
|
||||
'djcelery',
|
||||
]
|
||||
|
||||
TEST_RUNNER = 'django_nose.NoseTestSuiteRunner'
|
||||
AUTHENTICATION_BACKENDS = ('openstack_auth.backend.KeystoneBackend',)
|
||||
AUTHENTICATION_URLS = ['openstack_auth.urls']
|
||||
MESSAGE_STORAGE = 'django.contrib.messages.storage.fallback.FallbackStorage'
|
||||
|
||||
SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies'
|
||||
SESSION_COOKIE_HTTPONLY = True
|
||||
SESSION_EXPIRE_AT_BROWSER_CLOSE = True
|
||||
SESSION_COOKIE_SECURE = False
|
||||
SESSION_TIMEOUT = 1800
|
||||
# A token can be near the end of validity when a page starts loading, and
|
||||
# invalid during the rendering which can cause errors when a page load.
|
||||
# TOKEN_TIMEOUT_MARGIN defines a time in seconds we retrieve from token
|
||||
# validity to avoid this issue. You can adjust this time depending on the
|
||||
# performance of the infrastructure.
|
||||
TOKEN_TIMEOUT_MARGIN = 10
|
||||
|
||||
# When using cookie-based sessions, log error when the session cookie exceeds
|
||||
# the following size (common browsers drop cookies above a certain size):
|
||||
SESSION_COOKIE_MAX_SIZE = 4093
|
||||
|
||||
# when doing upgrades, it may be wise to stick to PickleSerializer
|
||||
# NOTE(berendt): Check during the K-cycle if this variable can be removed.
|
||||
# https://bugs.launchpad.net/horizon/+bug/1349463
|
||||
SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer'
|
||||
|
||||
LANGUAGES = (
|
||||
('de', 'German'),
|
||||
('en', 'English'),
|
||||
('en-au', 'Australian English'),
|
||||
('en-gb', 'British English'),
|
||||
('es', 'Spanish'),
|
||||
('fr', 'French'),
|
||||
('hi', 'Hindi'),
|
||||
('ja', 'Japanese'),
|
||||
('ko', 'Korean (Korea)'),
|
||||
('nl', 'Dutch (Netherlands)'),
|
||||
('pl', 'Polish'),
|
||||
('pt-br', 'Portuguese (Brazil)'),
|
||||
('ru', 'Russian'),
|
||||
('sr', 'Serbian'),
|
||||
('zh-cn', 'Simplified Chinese'),
|
||||
('zh-tw', 'Chinese (Taiwan)'),
|
||||
)
|
||||
LANGUAGE_CODE = 'en'
|
||||
LANGUAGE_COOKIE_NAME = 'horizon_language'
|
||||
USE_I18N = True
|
||||
USE_L10N = True
|
||||
USE_TZ = True
|
||||
|
||||
OPENSTACK_KEYSTONE_DEFAULT_ROLE = '_member_'
|
||||
|
||||
DEFAULT_EXCEPTION_REPORTER_FILTER = 'horizon.exceptions.HorizonReporterFilter'
|
||||
|
||||
POLICY_FILES_PATH = os.path.join(ROOT_PATH, "conf")
|
||||
# Map of local copy of service policy files
|
||||
POLICY_FILES = {
|
||||
'identity': 'keystone_policy.json',
|
||||
'compute': 'nova_policy.json',
|
||||
'volume': 'cinder_policy.json',
|
||||
'image': 'glance_policy.json',
|
||||
'orchestration': 'heat_policy.json',
|
||||
'network': 'neutron_policy.json',
|
||||
'telemetry': 'ceilometer_policy.json',
|
||||
}
|
||||
|
||||
SECRET_KEY = None
|
||||
LOCAL_PATH = None
|
||||
|
||||
SECURITY_GROUP_RULES = {
|
||||
'all_tcp': {
|
||||
'name': _('All TCP'),
|
||||
'ip_protocol': 'tcp',
|
||||
'from_port': '1',
|
||||
'to_port': '65535',
|
||||
},
|
||||
'all_udp': {
|
||||
'name': _('All UDP'),
|
||||
'ip_protocol': 'udp',
|
||||
'from_port': '1',
|
||||
'to_port': '65535',
|
||||
},
|
||||
'all_icmp': {
|
||||
'name': _('All ICMP'),
|
||||
'ip_protocol': 'icmp',
|
||||
'from_port': '-1',
|
||||
'to_port': '-1',
|
||||
},
|
||||
}
|
||||
|
||||
ADD_INSTALLED_APPS = []
|
||||
|
||||
# STATIC directory for custom theme, set as default.
|
||||
# It can be overridden in local_settings.py
|
||||
CUSTOM_THEME_PATH = 'static/themes/default'
|
||||
|
||||
try:
|
||||
from local.local_settings import * # noqa
|
||||
except ImportError:
|
||||
logging.warning("No local_settings file found.")
|
||||
|
||||
if not WEBROOT.endswith('/'):
|
||||
WEBROOT += '/'
|
||||
if LOGIN_URL is None:
|
||||
LOGIN_URL = WEBROOT + 'auth/login/'
|
||||
if LOGOUT_URL is None:
|
||||
LOGOUT_URL = WEBROOT + 'auth/logout/'
|
||||
if LOGIN_REDIRECT_URL is None:
|
||||
LOGIN_REDIRECT_URL = WEBROOT
|
||||
|
||||
MEDIA_ROOT = os.path.abspath(os.path.join(ROOT_PATH, '..', 'media'))
|
||||
MEDIA_URL = WEBROOT + 'media/'
|
||||
STATIC_ROOT = os.path.abspath(os.path.join(ROOT_PATH, '..', 'static'))
|
||||
STATIC_URL = WEBROOT + 'static/'
|
||||
STATICFILES_DIRS = get_staticfiles_dirs(WEBROOT)
|
||||
|
||||
CUSTOM_THEME = os.path.join(ROOT_PATH, CUSTOM_THEME_PATH)
|
||||
STATICFILES_DIRS.append(
|
||||
('custom', CUSTOM_THEME),
|
||||
)
|
||||
|
||||
# Load the pluggable dashboard settings
|
||||
import openstack_dashboard.enabled
|
||||
import openstack_dashboard.local.enabled
|
||||
from openstack_dashboard.utils import settings
|
||||
|
||||
INSTALLED_APPS = list(INSTALLED_APPS) # Make sure it's mutable
|
||||
settings.update_dashboards(
|
||||
[
|
||||
openstack_dashboard.enabled,
|
||||
openstack_dashboard.local.enabled,
|
||||
],
|
||||
HORIZON_CONFIG,
|
||||
INSTALLED_APPS,
|
||||
)
|
||||
INSTALLED_APPS[0:0] = ADD_INSTALLED_APPS
|
||||
|
||||
# Ensure that we always have a SECRET_KEY set, even when no local_settings.py
|
||||
# file is present. See local_settings.py.example for full documentation on the
|
||||
# horizon.utils.secret_key module and its use.
|
||||
if not SECRET_KEY:
|
||||
if not LOCAL_PATH:
|
||||
LOCAL_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)),
|
||||
'local')
|
||||
|
||||
from horizon.utils import secret_key
|
||||
SECRET_KEY = secret_key.generate_or_read_from_file(os.path.join(LOCAL_PATH,
|
||||
'.secret_key_store'))
|
||||
|
||||
from openstack_dashboard import policy_backend
|
||||
POLICY_CHECK_FUNCTION = policy_backend.check
|
||||
|
||||
# Add HORIZON_CONFIG to the context information for offline compression
|
||||
COMPRESS_OFFLINE_CONTEXT = {
|
||||
'STATIC_URL': STATIC_URL,
|
||||
'HORIZON_CONFIG': HORIZON_CONFIG,
|
||||
}
|
||||
|
||||
if DEBUG:
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
|
||||
# during django reloads and an active user is logged in, the monkey
|
||||
# patch below will not otherwise be applied in time - resulting in developers
|
||||
# appearing to be logged out. In typical production deployments this section
|
||||
# below may be omitted, though it should not be harmful
|
||||
from openstack_auth import utils as auth_utils
|
||||
auth_utils.patch_middleware_get_user()
|
0
Horizon/openstack_dashboard/dashboards/admin/hypervisors/baremetal/__init__.py → Horizon/rackhd/__init__.py
Normal file → Executable file
0
Horizon/openstack_dashboard/dashboards/admin/hypervisors/baremetal/__init__.py → Horizon/rackhd/__init__.py
Normal file → Executable file
22
Horizon/openstack_dashboard/dashboards/admin/hypervisors/baremetal/forms.py → Horizon/rackhd/forms.py
Normal file → Executable file
22
Horizon/openstack_dashboard/dashboards/admin/hypervisors/baremetal/forms.py → Horizon/rackhd/forms.py
Normal file → Executable file
@ -20,7 +20,7 @@ from horizon import forms
|
||||
from horizon import messages
|
||||
|
||||
from openstack_dashboard import api
|
||||
from openstack_dashboard.dashboards.admin.hypervisors.baremetal import shovel
|
||||
from openstack_dashboard.dashboards.admin.rackhd import shovel
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
@ -30,7 +30,7 @@ class RegisterForm(forms.SelfHandlingForm):
|
||||
driver = forms.ChoiceField(label=_('Driver'), required=True,
|
||||
widget=forms.Select(attrs={'class': 'switchable','data-slug': 'driver'}))
|
||||
kernel = forms.ChoiceField(label=_('Deploy Kernel'), required=True,
|
||||
widget=forms.Select(attrs={'class': 'switchable'}))
|
||||
widget=forms.Select(attrs={'class': 'switchable'}))
|
||||
ramdisk = forms.ChoiceField(label=_('Deploy RAM Disk'), required=True,
|
||||
widget=forms.Select(attrs={'class': 'switchable'}))
|
||||
port = forms.ChoiceField(label=_('Mac address'), required=True,
|
||||
@ -50,11 +50,11 @@ class RegisterForm(forms.SelfHandlingForm):
|
||||
widget=forms.PasswordInput(attrs={'class': 'switched','data-switch-on': 'driver','data-driver-pxe_ssh': _('SSH Password')}))
|
||||
sshport = forms.CharField(required=False,
|
||||
widget=forms.TextInput(attrs={'class': 'switched','data-switch-on': 'driver','data-driver-pxe_ssh': _('SSH Port')}))
|
||||
|
||||
failovernode = forms.ChoiceField(label=_("Failover Node"), required=False)
|
||||
enfailover = forms.BooleanField(label=_("Enable Failover"), initial=False, required=False)
|
||||
eventre = forms.CharField(max_length=255, label=_('Event Trigger (regex)'), required=False, initial='')
|
||||
|
||||
|
||||
failovernode = forms.ChoiceField(label=_("Failover Node"), required=False)
|
||||
enfailover = forms.BooleanField(label=_("Enable Failover"), initial=False, required=False)
|
||||
eventre = forms.CharField(max_length=255, label=_('Event Trigger (regex)'), required=False, initial='')
|
||||
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
super(RegisterForm, self).__init__(request, *args, **kwargs)
|
||||
self._node = kwargs['initial'].get('node', None)
|
||||
@ -65,7 +65,7 @@ class RegisterForm(forms.SelfHandlingForm):
|
||||
self.fields['name'].initial = shovel.get_catalog_data_by_source(self._node['id'],'dmi')['System Information']['Product Name']
|
||||
self.fields['uuid'].initial = self._node['id']
|
||||
self.fields['driver'].choices = [ (elem,_(elem)) for elem in self._drivers ]
|
||||
self.fields['kernel'].choices = [ (elem,_(elem)) for elem in self._ramdisk ]
|
||||
self.fields['kernel'].choices = [ (elem,_(elem)) for elem in self._ramdisk ]
|
||||
self.fields['ramdisk'].choices = [ (elem,_(elem)) for elem in self._ramdisk ]
|
||||
self.fields['port'].choices = [ (elem,_(elem)) for elem in self._macaddress]
|
||||
# BMC information initials
|
||||
@ -84,7 +84,7 @@ class RegisterForm(forms.SelfHandlingForm):
|
||||
nodes = shovel.request_nodes_get()
|
||||
self.fields['failovernode'].choices = [ (n['id'],_(n['id'])) for n in nodes if n['id'] != self._node['id'] ]
|
||||
else:
|
||||
redirect = reverse('horizon:admin:hypervisors:index')
|
||||
redirect = reverse('horizon:admin:rackhd:index')
|
||||
msg = 'Invalid node ID specified'
|
||||
messages.error(request, _(msg))
|
||||
raise ValueError(msg)
|
||||
@ -107,7 +107,7 @@ class RegisterForm(forms.SelfHandlingForm):
|
||||
messages.success(request, msg)
|
||||
return True
|
||||
except Exception:
|
||||
redirect = reverse('horizon:admin:hypervisors:index')
|
||||
redirect = reverse('horizon:admin:rackhd:index')
|
||||
msg = _('Failed to register baremetal node: {0} ({1})'.format(data['uuid'], data['name']))
|
||||
messages.error(request, msg)
|
||||
return False
|
||||
@ -141,7 +141,7 @@ class UnregisterForm(forms.SelfHandlingForm):
|
||||
else:
|
||||
raise Exception(result)
|
||||
except Exception:
|
||||
redirect = reverse('horizon:admin:hypervisors:index')
|
||||
redirect = reverse('horizon:admin:rackhd:index')
|
||||
msg = _('Failed to unregister baremetal node: {0}'.format(data['uuid']))
|
||||
messages.error(request, msg)
|
||||
return False
|
0
Horizon/openstack_dashboard/dashboards/admin/hypervisors/baremetal/json2html.py → Horizon/rackhd/json2html.py
Normal file → Executable file
0
Horizon/openstack_dashboard/dashboards/admin/hypervisors/baremetal/json2html.py → Horizon/rackhd/json2html.py
Normal file → Executable file
19
Horizon/rackhd/panel.py
Executable file
19
Horizon/rackhd/panel.py
Executable file
@ -0,0 +1,19 @@
|
||||
# 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.utils.translation import ugettext_lazy as _
|
||||
|
||||
import horizon
|
||||
class Rackhd(horizon.Panel):
|
||||
name = _("RackHD")
|
||||
slug = "rackhd"
|
||||
permissions = ('openstack.roles.admin',)
|
3
Horizon/openstack_dashboard/dashboards/admin/hypervisors/baremetal/shovel.py → Horizon/rackhd/shovel.py
Normal file → Executable file
3
Horizon/openstack_dashboard/dashboards/admin/hypervisors/baremetal/shovel.py → Horizon/rackhd/shovel.py
Normal file → Executable file
@ -20,9 +20,8 @@ from horizon import exceptions
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
SHOVEL_URL = 'http://10.240.19.192:9005'
|
||||
SHOVEL_BASE_API = '/api/1.1'
|
||||
URI = SHOVEL_URL + SHOVEL_BASE_API
|
||||
URI = "http://10.240.19.171:9005" + SHOVEL_BASE_API
|
||||
|
||||
def get_driver_list():
|
||||
r = requests.get(URI + '/ironic/drivers')
|
17
Horizon/openstack_dashboard/dashboards/admin/hypervisors/baremetal/tables.py → Horizon/rackhd/tables.py
Normal file → Executable file
17
Horizon/openstack_dashboard/dashboards/admin/hypervisors/baremetal/tables.py → Horizon/rackhd/tables.py
Normal file → Executable file
@ -27,7 +27,7 @@ class RegisterSelectedNodes(tables.LinkAction):
|
||||
verbose_name = _("Register Selected")
|
||||
icon = "plus"
|
||||
classes = ("ajax-modal",)
|
||||
url = "horizon:admin:hypervisors:baremetal:register"
|
||||
url = "horizon:admin:rackhd:register"
|
||||
def get_link_url(self, datum=None, *args, **kwargs):
|
||||
return reverse(self.url)
|
||||
|
||||
@ -37,7 +37,7 @@ class UnregisterSelectedNodes(tables.LinkAction):
|
||||
verbose_name = _("Unegister Selected")
|
||||
icon = "minus"
|
||||
classes = ("ajax-modal",)
|
||||
url = "horizon:admin:hypervisors:baremetal:unregister"
|
||||
url = "horizon:admin:rackhd:unregister"
|
||||
def get_link_url(self, datum=None, *args, **kwargs):
|
||||
return reverse(self.url)
|
||||
|
||||
@ -47,7 +47,7 @@ class RegisterNode(tables.LinkAction):
|
||||
verbose_name = _("Register")
|
||||
icon = "plus"
|
||||
classes = ("ajax-modal",)
|
||||
url = "horizon:admin:hypervisors:baremetal:register"
|
||||
url = "horizon:admin:rackhd:register"
|
||||
|
||||
|
||||
class Failover(tables.LinkAction):
|
||||
@ -55,7 +55,7 @@ class Failover(tables.LinkAction):
|
||||
verbose_name = _("Failover")
|
||||
icon = "minus"
|
||||
classes = ("ajax-modal",)
|
||||
url = "horizon:admin:hypervisors:baremetal:failover"
|
||||
url = "horizon:admin:rackhd:failover"
|
||||
|
||||
|
||||
class UnregisterNode(tables.LinkAction):
|
||||
@ -63,7 +63,7 @@ class UnregisterNode(tables.LinkAction):
|
||||
verbose_name = _("Unregister")
|
||||
icon = "minus"
|
||||
classes = ("ajax-modal",)
|
||||
url = "horizon:admin:hypervisors:baremetal:unregister"
|
||||
url = "horizon:admin:rackhd:unregister"
|
||||
|
||||
|
||||
class BareMetalFilterAction(tables.FilterAction):
|
||||
@ -113,14 +113,15 @@ class BareMetalAllEventsTable(tables.DataTable):
|
||||
|
||||
|
||||
class BareMetalTable(tables.DataTable):
|
||||
name = tables.Column('name', verbose_name=_('Name'), link="horizon:admin:hypervisors:baremetal:detail", )
|
||||
name = tables.Column('name', verbose_name=_('Name'), link="horizon:admin:rackhd:detail", )
|
||||
uuid = tables.Column('uuid', verbose_name=_('Node ID') )
|
||||
hwaddr = tables.Column('hwaddr', verbose_name=_('MAC Address') )
|
||||
events = tables.Column('events', verbose_name=_('Events'), link="horizon:admin:hypervisors:baremetal:events" )
|
||||
events = tables.Column('events', verbose_name=_('Events'), link="horizon:admin:rackhd:events" )
|
||||
state = tables.Column('state', verbose_name=_('State'))
|
||||
class Meta(object):
|
||||
name = "baremetal"
|
||||
verbose_name = _("RackHD")
|
||||
verbose_name = _("Baremetal Compute Nodes")
|
||||
table_actions = (BareMetalFilterAction,)
|
||||
multi_select = False
|
||||
row_actions = (RegisterNode, UnregisterNode,)
|
||||
|
@ -3,7 +3,7 @@
|
||||
{% load url from future %}
|
||||
|
||||
{% block form_id %}register_form{% endblock %}
|
||||
{% block form_action %}{% url 'horizon:admin:hypervisors:baremetal:register' baremetal %}{% endblock %}
|
||||
{% block form_action %}{% url 'horizon:admin:rackhd:register' baremetal %}{% endblock %}
|
||||
|
||||
{% block modal-header %}{% trans "Register Node" %}{% endblock %}
|
||||
|
@ -3,7 +3,7 @@
|
||||
{% load url from future %}
|
||||
|
||||
{% block form_id %}unregister_form{% endblock %}
|
||||
{% block form_action %}{% url 'horizon:admin:hypervisors:baremetal:unregister' baremetal %}{% endblock %}
|
||||
{% block form_action %}{% url 'horizon:admin:rackhd:unregister' baremetal %}{% endblock %}
|
||||
|
||||
{% block modal-header %}{% trans "Unregister Node" %}{% endblock %}
|
||||
|
@ -3,10 +3,10 @@
|
||||
{% block title %}{% trans "Node Events" %}{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
<div id="last-event">
|
||||
{{ lastevent_table.render }}
|
||||
</div>
|
||||
<div id="all-events">
|
||||
{{ allevents_table.render }}
|
||||
<div id="last-event">
|
||||
{{ lastevent_table.render }}
|
||||
</div>
|
||||
<div id="all-events">
|
||||
{{ allevents_table.render }}
|
||||
</div>
|
||||
{% endblock %}
|
@ -3,5 +3,5 @@
|
||||
{% block title %}{% trans "Register" %}{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
{% include 'admin/hypervisors/baremetal/_register.html' %}
|
||||
{% include 'admin/rackhd/_register.html' %}
|
||||
{% endblock %}
|
@ -3,5 +3,5 @@
|
||||
{% block title %}{% trans "Unregister" %}{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
{% include 'admin/hypervisors/baremetal/_unregister.html' %}
|
||||
{% include 'admin/rackhd/_unregister.html' %}
|
||||
{% endblock %}
|
19
Horizon/rackhd/tests.py
Executable file
19
Horizon/rackhd/tests.py
Executable file
@ -0,0 +1,19 @@
|
||||
# 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 horizon.test import helpers as test
|
||||
|
||||
|
||||
class RackhdTests(test.TestCase):
|
||||
# Unit tests for rackhd.
|
||||
def test_me(self):
|
||||
self.assertTrue(1 + 1 == 2)
|
11
Horizon/openstack_dashboard/dashboards/admin/hypervisors/baremetal/urls.py → Horizon/rackhd/urls.py
Normal file → Executable file
11
Horizon/openstack_dashboard/dashboards/admin/hypervisors/baremetal/urls.py → Horizon/rackhd/urls.py
Normal file → Executable file
@ -2,7 +2,7 @@
|
||||
# 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
|
||||
# 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
|
||||
@ -12,14 +12,17 @@
|
||||
|
||||
from django.conf.urls import patterns
|
||||
from django.conf.urls import url
|
||||
from django.conf.urls import include
|
||||
|
||||
from openstack_dashboard.dashboards.admin.rackhd import views
|
||||
|
||||
from openstack_dashboard.dashboards.admin.hypervisors.baremetal import views
|
||||
|
||||
urlpatterns = patterns(
|
||||
'openstack_dashboard.dashboards.admin.hypervisors.baremetal.views',
|
||||
'openstack_dashboard.dashboards.admin.rackhd.views',
|
||||
url(r'^$', views.IndexView.as_view(), name='index'),
|
||||
url(r'^(?P<baremetal>[^/]+)/register$', views.RegisterView.as_view(), name='register'),
|
||||
url(r'^(?P<baremetal>[^/]+)/unregister$', views.UnregisterView.as_view(), name='unregister'),
|
||||
url(r'^(?P<baremetal>[^/]+)/detail$', views.BareMetalDetailView.as_view(), name='detail'),
|
||||
url(r'^(?P<baremetal>[^/]+)/events$', views.BareMetalEventView.as_view(), name='events'),
|
||||
url(r'^(?P<baremetal>[^/]+)/failover$', views.FailoverView.as_view(), name='failover'),
|
||||
)
|
||||
)
|
83
Horizon/openstack_dashboard/dashboards/admin/hypervisors/baremetal/views.py → Horizon/rackhd/views.py
Normal file → Executable file
83
Horizon/openstack_dashboard/dashboards/admin/hypervisors/baremetal/views.py → Horizon/rackhd/views.py
Normal file → Executable file
@ -2,14 +2,13 @@
|
||||
# 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
|
||||
# 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
|
||||
import json
|
||||
import pprint
|
||||
@ -24,23 +23,71 @@ from horizon import tables
|
||||
from horizon import messages
|
||||
|
||||
from openstack_dashboard import api
|
||||
from openstack_dashboard.dashboards.admin.hypervisors.baremetal \
|
||||
|
||||
from openstack_dashboard.dashboards.admin.rackhd \
|
||||
import forms as baremetal_forms
|
||||
from openstack_dashboard.dashboards.admin.hypervisors.baremetal \
|
||||
from openstack_dashboard.dashboards.admin.rackhd \
|
||||
import tables as baremetal_tables
|
||||
|
||||
from openstack_dashboard.dashboards.admin.hypervisors.baremetal import shovel
|
||||
from openstack_dashboard.dashboards.admin.hypervisors.baremetal \
|
||||
from openstack_dashboard.dashboards.admin.rackhd \
|
||||
import json2html as j2h
|
||||
|
||||
import json
|
||||
from openstack_dashboard.dashboards.admin.rackhd import shovel
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
class IndexView(tables.DataTableView):
|
||||
# A very simple class-based view...
|
||||
table_class = baremetal_tables.BareMetalTable
|
||||
template_name = "admin/rackhd/index.html"
|
||||
page_title = _("Baremetal")
|
||||
|
||||
class NodeData:
|
||||
def __init__(self, uuid, name, hwaddr, events, state):
|
||||
self.id = uuid
|
||||
self.name = name
|
||||
self.uuid = uuid
|
||||
self.hwaddr = hwaddr
|
||||
self.events = events
|
||||
self.state = state
|
||||
|
||||
def get_data(self):
|
||||
data = []
|
||||
try:
|
||||
nodes = shovel.request_nodes_get()
|
||||
i = 0
|
||||
for n in nodes:
|
||||
dmi = shovel.get_catalog_data_by_source(n['id'],'dmi')
|
||||
name = dmi['System Information']['Product Name']
|
||||
hwaddr = n['name']
|
||||
id = n['id']
|
||||
events = '0'
|
||||
n = self._find_ironic_node(id)
|
||||
if n is not None:
|
||||
events = n['extra'].get('eventcnt','0')
|
||||
state = 'Registered'
|
||||
else:
|
||||
state = 'Unregistered'
|
||||
i += i +1
|
||||
data.append(self.NodeData(id, name, hwaddr, events, state))
|
||||
return data
|
||||
except Exception, e:
|
||||
print
|
||||
LOG.error("Excepton in get_baremetal_data(): {0}".format(e))
|
||||
return data
|
||||
def _find_ironic_node(self, id):
|
||||
# ISSUE: iterating all nodes because query by name (onrack id) isn't working in ironic?
|
||||
nodes = shovel.get_ironic_nodes()
|
||||
for n in nodes['nodes']:
|
||||
if n['extra'].get('nodeid', None) == id:
|
||||
return n
|
||||
return None
|
||||
|
||||
class RegisterView(forms.ModalFormView):
|
||||
context_object_name = 'baremetal'
|
||||
template_name = 'admin/hypervisors/baremetal/register.html'
|
||||
template_name = 'admin/rackhd/register.html'
|
||||
form_class = baremetal_forms.RegisterForm
|
||||
success_url = reverse_lazy('horizon:admin:hypervisors:index')
|
||||
success_url = reverse_lazy('horizon:admin:rackhd:index')
|
||||
page_title = _("Register Node")
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
@ -64,9 +111,9 @@ class RegisterView(forms.ModalFormView):
|
||||
|
||||
class UnregisterView(forms.ModalFormView):
|
||||
context_object_name = 'baremetal'
|
||||
template_name = 'admin/hypervisors/baremetal/unregister.html'
|
||||
template_name = 'admin/rackhd/unregister.html'
|
||||
form_class = baremetal_forms.UnregisterForm
|
||||
success_url = reverse_lazy('horizon:admin:hypervisors:index')
|
||||
success_url = reverse_lazy('horizon:admin:rackhd:index')
|
||||
page_title = _("Unegister Node")
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
@ -84,9 +131,9 @@ class UnregisterView(forms.ModalFormView):
|
||||
|
||||
class FailoverView(forms.ModalFormView):
|
||||
context_object_name = 'baremetal'
|
||||
template_name = 'admin/hypervisors/baremetal/register.html'
|
||||
template_name = 'admin/rackhd/register.html'
|
||||
form_class = baremetal_forms.RegisterForm
|
||||
success_url = reverse_lazy('horizon:admin:hypervisors:index')
|
||||
success_url = reverse_lazy('horizon:admin:rackhd:index')
|
||||
page_title = _("Failover")
|
||||
|
||||
def _find_ironic_node(self, id):
|
||||
@ -100,7 +147,7 @@ class FailoverView(forms.ModalFormView):
|
||||
result = shovel.unregister_node_del(id)
|
||||
return True
|
||||
except Exception:
|
||||
redirect = reverse('horizon:admin:hypervisors:index')
|
||||
redirect = reverse('horizon:admin:rackhd:index')
|
||||
return False
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
@ -125,7 +172,7 @@ class FailoverView(forms.ModalFormView):
|
||||
else:
|
||||
raise ValueError('Registered node not found')
|
||||
except ValueError as e:
|
||||
redirect = reverse('horizon:admin:hypervisors:index')
|
||||
redirect = reverse('horizon:admin:rackhd:index')
|
||||
messages.error(self.request, _(e.message))
|
||||
raise Exception(e.message)
|
||||
self._remove_node(current_id)
|
||||
@ -135,7 +182,7 @@ class FailoverView(forms.ModalFormView):
|
||||
|
||||
class BareMetalDetailView(tables.DataTableView):
|
||||
table_class = baremetal_tables.BareMetalDetailsTable
|
||||
template_name = 'admin/hypervisors/baremetal/detail.html'
|
||||
template_name = 'admin/rackhd/detail.html'
|
||||
page_title = _('Details')
|
||||
|
||||
class CatalogData:
|
||||
@ -158,7 +205,7 @@ class BareMetalDetailView(tables.DataTableView):
|
||||
class BareMetalEventView(tables.MultiTableView):
|
||||
table_classes = (baremetal_tables.BareMetalLastEventTable,
|
||||
baremetal_tables.BareMetalAllEventsTable,)
|
||||
template_name = 'admin/hypervisors/baremetal/events.html'
|
||||
template_name = 'admin/rackhd/events.html'
|
||||
page_title = _('Events')
|
||||
name = _("Events")
|
||||
slug = "events"
|
||||
@ -208,7 +255,7 @@ class BareMetalEventView(tables.MultiTableView):
|
||||
try:
|
||||
sel = shovel.get_current_sel_data(id)[0].get('sel', [])
|
||||
except KeyError as e:
|
||||
redirect = reverse('horizon:admin:hypervisors:index')
|
||||
redirect = reverse('horizon:admin:rackhd:index')
|
||||
messages.error(self.request, _('No SEL data available, check node {0} poller task'.format(id)))
|
||||
raise KeyError(e.message)
|
||||
data = []
|
Loading…
x
Reference in New Issue
Block a user