20141001 delapsley-oc-openstack-final
-
Upload
david-lapsley -
Category
Internet
-
view
310 -
download
5
Transcript of 20141001 delapsley-oc-openstack-final
Enhancing OpenStack Horizon with AngularJS
#openstackmeetupoc
David Lapsley@devlaps, [email protected]
October 1, 2014
OpenStack Horizon in Action
Launching an Instance
Admin Overview
Project Overview
Launching an Instance
Launching an Instance
Launching an Instance
Launching an Instance
Launching an Instance
Launching an Instance
OpenStack CloudsArchitecture and Model
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)
OpenStack HorizonArchitecture
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
Django Stack
Horizon Stack
Horizon UINav entries
Column sorting
Linking
RPCData retrieval
Row actions
Table actionsFiltering
Multi-select
Customized UI
AngularJS
AngularJS lets you extend HTML
vocabulary for your application. The
resulting environment is extraordinarily
expressive, readable, and quick to
develop.https://angularjs.org
Develop smaller, lighter web apps that
are simple to create and easy to test,
extend and maintain as they grow
Brad Green, Shyam Seshadri, “AngularJS”
Core concepts
● Model View Controller framework
● Client-side templates
● Data binding
● Dependency injection
Hello Worldindex.html
<html ng-app><head> <script src="angular.js"></script> <script src="controllers.js"></script></head><body> <div ng-controller='HelloController'> <p>{{greeting.text}}, World</p> <button ng-click="action()">Alert</button> </div></body></html>
controllers.js
function HelloController($scope) { $scope.greeting = { text: 'Hello' }; $scope.action = function() { alert('Action!'); };}
AngularJSBy: Brad Green; Shyam SeshadriPublisher: O'Reilly Media, Inc.Pub. Date: April 23, 2013
Hello World
Hello World
AngularJS + Horizon
Horizon Stack Extended
Adding a new PanelUsing current Horizon
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 Structureopenstackoc/ __init__.py dashboard.py templates/
openstackoc/ static/
openstackoc/ css/ img/ js/
_10_openstackoc.py
DASHBOARD = 'openstackoc'
DISABLED = False
ADD_INSTALLED_APPS = [
'openstack_dashboard.dashboards.openstackoc',
]
dashboard.pyclass BasePanelGroup(horizon.PanelGroup): slug = "overview" name = _("Overview") panels = ("hypervisors",)
class OpenstackOC(horizon.Dashboard): name = _("OpenstackOC") slug = "OpenstackOC" panels = (BasePanelGroup,) default_panel = "hypervisors" roles = ("admin",)
horizon.register(OpenstackOC)
DashboardDashboard
PanelGroup
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 Structureopenstackoc/ hypervisors/
__init__.py panel.py urls.py views.py
tests.py tables.py templates/
openstackoc/ hypervisors/ index.html static/
openstackoc/ hypervisors /
panel.py
from django.utils.translation import ugettext_lazy as _ import horizon from openstack_dashboard.dashboards.openstackoc import dashboard class Hypervisors(horizon.Panel): name = _("Hypervisors") slug = 'hypervisors' dashboard.OpenstackOC.register(Hypervisors)
DashboardDashboard
PanelGroup
Panel
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 = ’openstackoc/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><div class="row-fluid"> <div class="col-sm-12"> {{ tab_group.render }} </div></div>{% endblock %}
URLs Modules● Provides URL to View mappings
urls.py
from django.conf.urls import patterns from django.conf.urls import url
from openstack_dashboard.dashboards.openstackoc.hypervisors import views
urlpatterns = patterns( 'openstack_dashboard.dashboards.openstackoc.hypervisors.views' url(r'^$', views.IndexView.as_view(), name='index'),)
Completed DashboardNav entries
Column sorting
Panel rendering
Linking
RPCData retrieval
Adding a new Panelwith AngularJS
Directory Structureopenstackoc/ hypervisors/
__init__.py panel.py urls.py views.py
tables.py tests.py templates/openstackoc/hypervisors/ index.html static/openstackoc/hypervisors/js/ hypervisors-controller.jsrest/nova/ __init__.py hypervisor.py instance.py
REST Resource● Provides the source of data via RESTful API
● Resource includes/provides:o entity data/stateo configurable table_actions and
row_actionso sortingo paginationo CRUD operations
hypervisors.pyclass HypervisorResource(resource.BaseNovaResource):
pk = fields.CharField(attribute="pk", _("Primary Key"), hidden=True) hypervisor_hostname = fields.CharField(attribute='hypervisor_hostname', sortable=True, searchable=True) … actions = fields.ActionsField(attribute='actions', actions=[HypervisorViewLiveStats, HypervisorEnableAction, HypervisorDisableAction], title=_("Actions"), sortable=True) class Meta: authorization = auth.RestAuthorization() list_allowed_methods = ['get'] resource_name = '^hypervisor' field_order = ['pk', 'hypervisor_hostname', 'hypervisor_type', 'vcpus', 'vcpus_used', 'memory_mb', 'memory_mb_used', 'running_vms', 'state', 'status', 'actions']
Controller
● Controls view logic
hypervisor-controller.jshorizonApp.controller('TableController', function($scope, $http) { $scope.headers = headers; $scope.title = title; $http.get('/rest/api/v1/nova/instance/').success( function(data, status, headers, config) { $scope.instances = data; }); });
horizonApp.controller('ActionDropdownController', function($scope) { $scope.status = { isopen: false }; $scope.toggleDropdown = function($event) { $event.preventDefault(); $event.stopPropagation(); $scope.status.isopen = !$scope.status.isopen; }; $scope.action = function(action, id) { // Perform action. }; … });
View
● In AngularJS, view is defined in the
HTML template
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 %}
index.html
<div ng-controller="TableController"> <table class="..."> <thead> <tr class="..."> <th class="..."> <h3 class="...">{$ title $}</h3> </th> </tr> <tr class="..."> <th class="..." ng-repeat='header in headers'> <div class="...">{$ header.name $}</div> </th> </tr> </thead>
index.html <tr ng-repeat="instance in instances"> <td ng-repeat="datum in instance.data">{$ datum $}</td> <td class="..."> <div ng-controller="ActionDropdownController"> <div class="..." dropdown> <button class="..." ng-click="action(instance.actions[0], instance.name)"> {$ instance.actions[0].verbose_name $} </button> ... <div class="..."> <li class="..." ng-repeat="action in instance.actions"> <a href="#" class="..." ng-click="$parent.action(action,parent.instance.name)"> {$ action.verbose_name $} </a> </li> </ul> </div> </td> </tr> </table>
Advantages
● Clean split between server and client
side
● Significantly cleaner, terser, easier to
understand client-side code
● Significant easier to improve UX
● Client- and server-side code can be
developed and tested independently
● Faster feature velocity
AngularJS + Horizon in Production
Client-side Rendering
“Full” dataset search
Cache up to 1K records client-side
“Full” pagination
Real-time Data Updates every 5s
Increased platform visibility
Every node instrumented
Historical MetricsUp to 1 year of
data
Increased platform visibility
Every node instrumented
Convenient access
OpenStack HorizonContributing
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
Thank You
David Lapsley@devlaps, [email protected]
If this sounds interesting…
http://jobs.metacloud.com
We are hiring!