20140821 delapsley-cloudopen-public
DESCRIPTION
The OpenStack project was launched by Rackspace and NASA in July 2010. Since then it has gained considerable momentum, with over 200 companies joining the project. Horizon is OpenStack’s web-based user interface. It is constructed in two parts: 1) a core set of libraries for implementing a dashboard; 2) a reference dashboard implementation that uses the core set of libraries. Customization is key to the Horizon framework. It allows developers to construct their own dashboards, panel groups, and panels, and assemble them via a common navigation/presentation framework. In this presentation, David will provide a brief introduction to OpenStack and Horizon. Then he will review Horizon’s architecture, explain how it integrates with other OpenStack services, examine its most interesting features, and describe how to start developing with it.TRANSCRIPT
OPENSTACK THAT JUST WORKS
OpenStack Horizon:Controlling the Cloud using Django
David Lapsley@devlaps, [email protected]
August 21, 2014
OpenStack Model
http://docs.openstack.org/openstack-ops/content/example_architecture.html
http://docs.openstack.org/training-guides/content/module001-ch004-openstack-architecture.html
OpenStack Projects
● Compute (Nova)
● Network (Nova, Neutron)
● VM Registration (Glance)
● Identity (Keystone)
● Object Storage (Swift, …)
● Block Storage (Cinder)
● Dashboard (Horizon)
Horizon Overview
● Django-based application deployed via
Apache and WSGI
● Provides access to OpenStack services
● Leverages existing technologieso Bootstrap, jQuery, Underscore.js,
AngularJS, D3.js, Rickshaw, LESS CSS
● Extends Django to enhance
extensibility
Dashboards & Panels
● Horizon provides a flexible framework
for creating Dashboards and Panels
● Panels grouped into PanelGroups
● PanelGroups into Dashboards
Dashboard App
● Dashboards created as Django
Applications
● Dashboard modules partitioned into:o statico templateso python modules
Directory Structurecloudopen/ __init__.py dashboard.py templates/
cloudopen/ static/
cloudopen/ css/ img/ js/
settings.py
INSTALLED_APPS = ( ... 'horizon', 'openstack_dashboard.dashboards.project', 'openstack_dashboard.dashboards.admin', 'openstack_dashboard.dashboards.metacloud', 'openstack_dashboard.dashboards.settings', 'openstack_dashboard.dashboards.cloudopen', ...)
dashboard.pyclass BasePanelGroup(horizon.PanelGroup): slug = "overview" name = _("Overview") panels = ("hypervisors",)
class CloudOpen(horizon.Dashboard): name = _("Cloudopen") slug = "cloudopen" panels = (BasePanelGroup,) default_panel = "hypervisors" roles = ("admin",)
horizon.register(CloudOpen)
Panel● Panels are created as Python Modules● Panel modules partitioned into:o static/o templates/o python modules:
urls.py, views.py, panel.pytables.py, forms.py, tabs.py, tests.py
Directory Structurecloudopen/ hypervisors/
__init__.py panel.py urls.py views.py
tests.py tables.py templates/
cloudopen/ hypervisors/ index.html static/
cloudopen/ hypervisors /
panel.py
from django.utils.translation import ugettext_lazy as _ import horizon from openstack_dashboard.dashboards.cloudopen import dashboard class Hypervisors(horizon.Panel): name = _(”Hypervisors") slug = 'hypervisors' dashboard.CloudOpen.register(Hypervisors)
View Module● View module ties together everything:o Tables, Templates, API Calls
● Horizon base views:o APIView, LoginView, MultiTableView,
DataTableView, MixedDataTableView, TabView,
TabbedTableView, WorkflowView
views.py
from horizon import tables
class HypervisorsIndexView(tables.DataTableView): table_class = hv_tables.AdminHypervisorsTable template_name = ’cloudopen/hypervisors/index.html’
def get_data(self): hypervisors = [] states = {} hypervisors = api.nova.hypervisor_list(self.request) … return hypervisors
Table Module● Table classes provide framework for tables: o consistent look and feelo configurable table_actions and
row_actionso select/multi-select columno sortingo pagination
● Functionality is split server- and client-side
tables.pyclass EnableAction(tables.BatchAction): …
class DisableAction(tables.BatchAction): name = 'disable' classes = ('btn-danger',) def allowed(self, request, hv): return hv.service.get('status') == 'enabled' def action(self, request, obj_id): hv = api.nova.hypervisor_get(request, obj_id) host = getattr(hv, hv.NAME_ATTR) return api.nova.service_disable(request, host, 'nova-compute')
def search_link(x): return '/admin/instances?q={0}'.format(x.hypervisor_hostname)
tables.pyclass AdminHypervisorsTable(tables.DataTable):
hypervisor_hostname = tables.Column( 'hypervisor_hostname', verbose_name=_('Hostname'))
state = tables.Column( lambda hyp: hyp.service.get('state', _('UNKNOWN')).title(), verbose_name=_('State'))
running_vms = tables.Column( 'running_vms', link=search_link, verbose_name=_('Instances'))
...
class Meta: name = 'hypervisors' verbose_name = _('Hypervisors') row_actions = (EnableAction, DisableAction)
Template
● Standard Django template format
● Typically leverage base horizon
templates (e.g. base.html)
index.html{% extends 'base.html' %} {% load i18n horizon humanize sizeformat %} {% block title %}{% trans 'Hypervisors' %}{% endblock %} {% block page_header %} {% include 'horizon/common/_page_header.html' with title=_('All Hypervisors') %} {% endblock page_header %} {% block main %}<div class="quota-dynamic"> <h3>{% trans "Hypervisor Summary" %}</h3> <div class="d3_quota_bar">
<div class="d3_pie_chart" …></div> </div> …</div>
{{ table.render }} {% endblock %}
urls.py
from django.conf.urls import patterns from django.conf.urls import url
from openstack_dashboard.dashboards.cloudopen.hypervisors import views
urlpatterns = patterns( 'openstack_dashboard.dashboards.cloudopen.hypervisors.views' url(r'^$', views.IndexView.as_view(), name='index'),)
Completed Dashboard!Nav entries
Column sorting
Panel rendering
Linking
RPCData retrieval
Row actions
Customization Hooks● Change Site Title, Logo, Brand Links● Modify Dashboards and Panels● Change Button Styles● Use Custom Stylesheets● Use Custom Javascript
Custom Overrides Module● For site-wide customization, Horizon allows for a
user-defined python customization module● Customizations can include:o Registering/unregistering panelso Modifying dashboard or panel attributeso Moving panels between dashboardso Modifying attributes of existing UI elements
local_settings.py
HORIZON_CONFIG = { ... 'customization_module': 'openstack_dashboard.dashboards.cloudopen.overrides', 'test_enabled': True, }
overrides.py
from openstack_dashboard.dashboards.cloudopen.test import panel\ as test_panel from openstack_dashboard.dashboards.cloudopen import dashboard \ as cloudopen_dashboard
from django.conf import settings import horizon
CLOUDOPEN_DASHBOARD_SETTINGS = horizon.get_dashboard('cloudopen')
if settings.HORIZON_CONFIG.get('test_enabled'): CLOUDOPEN_DASHBOARD_SETTINGS .register(test_panel.Tests)
Pluggable Settings
● Since Icehouse release, Horizon enables
pluggable settings to control structureo Enable/Disable new Dashboardso Add new PanelGroupso Add/Remove Panels to/from
PanelGroups
● Settings all live in:o openstack_dashboard/local/enabled
Pluggable Settings
_10_cloudopen.py
_20_cloudopen_add_panel_group.py
_30_tests_add_panel.py
__init__.py
Pluggable Settings
_10_cloudopen.py
DASHBOARD = 'cloudopen'
DISABLED = False
ADD_INSTALLED_APPS = [
'openstack_dashboard.dashboards.cloudopen',
]
Pluggable Settings
_20_cloudopen_add_panel_group.py
PANEL_GROUP = 'tests'
PANEL_GROUP_NAME = 'Tests'
PANEL_GROUP_DASHBOARD = 'cloudopen'
Pluggable Settings
_30_tests_add_panel.py
PANEL = 'test'
PANEL_DASHBOARD = 'cloudopen'
PANEL_GROUP = 'tests'
ADD_PANEL = \
'openstack_dashboard.dashboards.cloudopen.test.panel.Tests'
Pluggable Settings
_30_tests_add_panel.py
PANEL = 'test'
PANEL_DASHBOARD = 'cloudopen'
PANEL_GROUP = 'tests'
ADD_PANEL = \
'openstack_dashboard.dashboards.cloudopen.test.panel.Tests'
Pluggable Settings
_30_overview_add_panel.py
PANEL = 'test'
PANEL_DASHBOARD = 'cloudopen'
PANEL_GROUP = 'overview'
ADD_PANEL = \
'openstack_dashboard.dashboards.cloudopen.test.panel.Tests'
Custom CSS and Javascript● Horizon templates provides blocks for custom
CSS and Javascript● To add custom CSS/JS, can either extend existing
templates, or replace with your own custom
templates
base.html<!DOCTYPE html> <html> <head> <title>{% block title %}{% endblock %} - {% site_branding %}</title> {% block css %} {% include "_stylesheets.html" %} {% endblock %} . . . </head> <body id="{% block body_id %}{% endblock %}"> {% block content %} . . . {% endblock %} <div id="footer">{% block footer %}{% endblock %}</div> {% block js %} {% include "horizon/_scripts.html" %} {% endblock %} </body> </html>
index.html{% extends "base.html" %} {% load i18n %} {% block title %}{% trans "Volumes" %}{% endblock %}
{% block css %} {% include "cloudopen/_stylesheets.html" %} {% endblock %}
{% block page_header %} {% include "horizon/common/_page_header.html" with title=_("Volumes") %} {% endblock page_header %}
{% block main %} <div id="volumes">{{ volumes_table.render }}</div> <div id="volume-types">{{ volume_types_table.render }}</div> {% endblock %}
{% block js%} {% include "cloudopen/_scripts.html" %} {% endblock %}
Historical MetricsUp to 1 year of
data
Increased platform visibility
Every node instrumented
Convenient access
Devstack and Contributing● Devstack:o “A documented shell script to build complete
OpenStack development environments.”o http://devstack.org
● Contributing to Horizon:
– http://docs.openstack.org/developer/
horizon/contributing.html