openstack horizon 二次 开发 示例

一、环境

[root@localhost horizon]# cat /etc/redhat-release
CentOS Linux release 7.8.2003 (Core)
[root@localhost horizon]# python -V
Python 2.7.5
[root@localhost horizon]# pip -V
pip 20.2 from /usr/lib/python2.7/site-packages/pip (python 2.7)
[root@localhost horizon]# python3 -V
Python 3.7.7
[root@localhost horizon]# pip3 -V
pip 19.2.3 from /usr/local/python3/lib/python3.7/site-packages/pip (python 3.7)
[root@localhost horizon]# tox --version
3.18.0 imported from /usr/lib/python2.7/site-packages/tox/__init__.pyc
[root@localhost horizon]# pip list | grep horizon
horizon                          16.2.0

二、步骤

    本文假设已用源码方式部署成功本地运行的horizon环境,部署过程参考:
    https://blog.csdn.net/zhujisoft/article/details/107726414

     1、创建面板的典型结构

    在horizon目录下

$ mkdir openstack_dashboard/dashboards/mydashboard

$ tox -e manage -- startdash mydashboard \
  --target openstack_dashboard/dashboards/mydashboard

$ mkdir openstack_dashboard/dashboards/mydashboard/mypanel

$ tox -e manage -- startpanel mypanel \
  --dashboard=openstack_dashboard.dashboards.mydashboard \
  --target=openstack_dashboard/dashboards/mydashboard/mypanel

输出

[root@localhost horizon]# tox -e manage -- startpanel mypanel \
>   --dashboard=openstack_dashboard.dashboards.mydashboard \
>   --target=openstack_dashboard/dashboards/mydashboard/mypanel
/root/horizon/.tox/venv/lib/python3.7/site-packages/setuptools/depends.py:2: DeprecationWarning: the imp module is deprecated in favour of importlib; see the module's documentation for alternative uses
  import imp
manage develop-inst-noop: /root/horizon
manage installed: appdirs==1.4.3,asn1crypto==0.24.0,astroid==2.1.0,attrs==19.1.0,Babel==2.7.0,bandit==1.6.2,certifi==2019.6.16,cffi==1.12.3,chardet==3.0.4,cliff==2.16.0,cmd2==0.8.9,coverage==4.5.4,cryptography==2.7,debtcollector==1.22.0,decorator==4.4.0,Django==2.0.13,django-appconf==1.0.3,django-babel==0.6.2,django-compressor==2.3,django-debreach==1.5.2,django-pyscss==2.0.2,doc8==0.8.0,docutils==0.15.2,dogpile.cache==0.7.1,extras==1.0.0,fasteners==0.14.1,fixtures==3.0.0,flake8==2.6.2,flake8-import-order==0.12,futurist==1.9.0,gitdb2==2.0.5,GitPython==3.0.2,hacking==1.1.0,-e git+https://git.openstack.org/openstack/horizon@d83d58af1e247ca39f90fdb22d0005698540f520#egg=horizon,idna==2.8,iso8601==0.1.12,isort==5.2.0,jmespath==0.9.4,jsonpatch==1.24,jsonpointer==2.0,jsonschema==3.0.2,keystoneauth1==3.17.3,lazy-object-proxy==1.5.1,linecache2==1.0.0,mccabe==0.6.1,mock==3.0.5,monotonic==1.5,mox3==0.28.0,msgpack==0.6.1,munch==2.3.2,netaddr==0.7.19,netifaces==0.10.9,nodeenv==1.3.3,openstacksdk==0.36.4,os-client-config==1.33.0,os-service-types==1.7.0,osc-lib==1.14.1,oslo.concurrency==3.30.0,oslo.config==6.11.2,oslo.context==2.23.1,oslo.i18n==3.24.0,oslo.log==3.44.3,oslo.policy==2.3.4,oslo.serialization==2.29.2,oslo.upgradecheck==0.3.2,oslo.utils==3.41.6,osprofiler==2.8.2,pbr==5.4.3,Pint==0.9,prettytable==0.7.2,pycodestyle==2.6.0,pycparser==2.19,pyflakes==1.2.3,pyinotify==0.9.6,pylint==2.2.2,pymongo==3.9.0,pyOpenSSL==19.0.0,pyparsing==2.4.2,pyperclip==1.7.0,pyrsistent==0.15.4,pyScss==1.3.7,python-cinderclient==5.0.1,python-dateutil==2.8.0,python-glanceclient==2.17.1,python-keystoneclient==3.21.0,python-memcached==1.59,python-mimeparse==1.6.0,python-neutronclient==6.14.1,python-novaclient==15.1.1,python-swiftclient==3.8.1,pytz==2019.2,PyYAML==5.1.2,rcssmin==1.0.6,requests==2.22.0,requestsexceptions==1.4.0,restructuredtext-lint==1.3.0,rfc3986==1.3.2,rjsmin==1.1.0,selenium==3.141.0,semantic-version==2.8.2,simplejson==3.16.0,six==1.12.0,smmap2==2.0.5,stevedore==1.31.0,testscenarios==0.5.0,testtools==2.3.0,traceback2==1.4.0,unittest2==1.1.0,urllib3==1.25.3,warlock==1.3.3,wcwidth==0.1.7,WebOb==1.8.5,wrapt==1.11.2,XStatic==1.0.2,XStatic-Angular==1.5.8.0,XStatic-Angular-Bootstrap==2.2.0.0,XStatic-Angular-FileUpload==12.0.4.0,XStatic-Angular-Gettext==2.3.8.0,XStatic-Angular-lrdragndrop==1.0.2.4,XStatic-Angular-Schema-Form==0.8.13.0,XStatic-Bootstrap-Datepicker==1.3.1.0,XStatic-Bootstrap-SCSS==3.3.7.1,XStatic-bootswatch==3.3.7.0,XStatic-D3==3.5.17.0,XStatic-Font-Awesome==4.7.0.0,XStatic-Hogan==2.0.0.2,XStatic-Jasmine==2.4.1.2,XStatic-jQuery==1.12.4.1,XStatic-JQuery-Migrate==1.2.1.1,XStatic-jquery-ui==1.12.1.1,XStatic-JQuery.quicksearch==2.0.3.1,XStatic-JQuery.TableSorter==2.14.5.1,XStatic-JSEncrypt==2.3.1.1,XStatic-mdi==1.6.50.2,XStatic-objectpath==1.2.1.0,XStatic-Rickshaw==1.5.0.0,XStatic-roboto-fontface==0.5.0.0,XStatic-smart-table==1.4.13.2,XStatic-Spin==1.2.5.2,XStatic-term.js==0.0.7.0,XStatic-tv4==1.2.7.0,xvfbwrapper==0.2.9
manage run-test-pre: PYTHONHASHSEED='2063410502'
manage run-test: commands[0] | /root/horizon/.tox/venv/bin/python /root/horizon/manage.py startpanel mypanel --dashboard=openstack_dashboard.dashboards.mydashboard --target=openstack_dashboard/dashboards/mydashboard/mypanel
/root/horizon/.tox/venv/lib/python3.7/site-packages/django/db/models/fields/__init__.py:155: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated since Python 3.3,and in 3.9 it will stop working
  if isinstance(choices, collections.Iterator):
/root/horizon/.tox/venv/lib/python3.7/site-packages/django/db/models/sql/query.py:9: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated since Python 3.3,and in 3.9 it will stop working
  from collections import Counter, Iterator, Mapping, OrderedDict, namedtuple
/root/horizon/.tox/venv/lib/python3.7/site-packages/django/core/paginator.py:130: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated since Python 3.3,and in 3.9 it will stop working
  class Page(collections.Sequence):
DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated since Python 3.3,and in 3.9 it will stop workingDeprecationWarning: inspect.getargspec() is deprecated since Python 3.0, use inspect.signature() or inspect.getfullargspec()FutureWarning: Possible nested set at position 329_____________________________________________________________________________________________________ summary _____________________________________________________________________________________________________
  manage: commands succeeded
  congratulations :)

 

查看目录结构

[root@localhost horizon]# tree openstack_dashboard/dashboards/mydashboard
openstack_dashboard/dashboards/mydashboard
├── dashboard.py
├── __init__.py
├── mypanel
│   ├── __init__.py
│   ├── panel.py
│   ├── templates
│   │   └── mypanel
│   │       └── index.html
│   ├── tests.py
│   ├── urls.py
│   └── views.py
├── static
│   └── mydashboard
│       ├── js
│       │   └── mydashboard.js
│       └── scss
│           └── mydashboard.scss
└── templates
    └── mydashboard
        └── base.html

 结构中定义了mydashboard和mypanel,代码的层级结构和图形界面的对应关系如下:
这里写图片描述

2、增加代码

mydashboard/dashboard.py


from django.utils.translation import ugettext_lazy as _

import horizon


class Mygroup(horizon.PanelGroup):
    slug = "mygroup"
    name = _("My Group")
    panels = ('mypanel',)


class Mydashboard(horizon.Dashboard):
    name = _("My Dashboard")
    slug = "mydashboard"
    panels = (Mygroup,)  # Add your panels here.
    default_panel = 'mypanel'  # Specify the slug of the default panel.


horizon.register(Mydashboard)

mydashboard/mypanel/tables.py

from django.utils.translation import ugettext_lazy as _

from horizon import tables


class MyFilterAction(tables.FilterAction):
    name = "myfilter"


class InstancesTable(tables.DataTable):
    name = tables.Column('name', \
                         verbose_name=_("Name"))
    status = tables.Column('status', \
                           verbose_name=_("Status"))
    zone = tables.Column('availability_zone', \
                         verbose_name=_("Availability Zone"))
    image_name = tables.Column('image_name', \
                               verbose_name=_("Image Name"))

    class Meta(object):
        name = "instances"
        verbose_name = _("Instances")
        table_actions = (MyFilterAction,)

 mydashboard/mypanel/tabs.py

from django.utils.translation import ugettext_lazy as _

from horizon import exceptions
from horizon import tabs

from openstack_dashboard import api
from openstack_dashboard.dashboards.mydashboard.mypanel import tables


class InstanceTab(tabs.TableTab):
    name = _("Instances Tab")
    slug = "instances_tab"
    table_classes = (tables.InstancesTable,)
    template_name = ("horizon/common/_detail_table.html")
    preload = False

    def has_more_data(self, table):
        return self._has_more

    def get_instances_data(self):
        try:
            marker = self.request.GET.get(
                        tables.InstancesTable._meta.pagination_param, None)

            instances, self._has_more = api.nova.server_list(
                self.request,
                search_opts={'marker': marker, 'paginate': True})

            return instances
        except Exception:
            self._has_more = False
            error_message = _('Unable to get instances')
            exceptions.handle(self.request, error_message)

            return []

class MypanelTabs(tabs.TabGroup):
    slug = "mypanel_tabs"
    tabs = (InstanceTab,)
    sticky = True

mydashboard/mypanel/views.py

from horizon import tabs

from openstack_dashboard.dashboards.mydashboard.mypanel \
    import tabs as mydashboard_tabs


class IndexView(tabs.TabbedTableView):
    tab_group_class = mydashboard_tabs.MypanelTabs
    template_name = 'mydashboard/mypanel/index.html'

    def get_data(self, request, context, *args, **kwargs):
        # Add data to the context here...
        return context

mydashboard/mypanel/urls.py
 

from django.conf.urls import url

from openstack_dashboard.dashboards.mydashboard.mypanel import views


urlpatterns = [
    url(r'^$', views.IndexView.as_view(), name='index'),
]

 mydashboard/mypanel/templates/mypanel/index.html
 

{% extends 'base.html' %}
{% load i18n %}
{% block title %}{% trans "My Panel" %}{% endblock %}

{% block page_header %}
   {% include "horizon/common/_page_header.html" with title=_("My Panel") %}
{% endblock page_header %}

{% block main %}
<div class="row">
   <div class="col-sm-12">
   {{ tab_group.render }}
   </div>
</div>
{% endblock %}

#启用mydashboard 
horizon/openstack_dashboard/enabled/_50_mydashboard.py

 

# The name of the dashboard to be added to HORIZON['dashboards']. Required.
DASHBOARD = 'mydashboard'

# If set to True, this dashboard will not be added to the settings.
DISABLED = False

# A list of applications to be added to INSTALLED_APPS.
ADD_INSTALLED_APPS = [
    'openstack_dashboard.dashboards.mydashboard',
]

#本地设置
horizon/openstack_dashboard/local/local_settings.py

 

# https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts
ALLOWED_HOSTS = ['*', ]


# https://docs.djangoproject.com/en/1.11/topics/http/sessions/.
CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': '192.168.44.91:11211',
    },
}



OPENSTACK_HOST = "192.168.44.91"
OPENSTACK_KEYSTONE_URL = "http://%s:5000/v3" % OPENSTACK_HOST


3、运行

tox -e runserver 0:9000

访问localhost:9000

 

三、参考文档

https://docs.openstack.org/horizon/rocky/contributor/tutorials/dashboard.html

https://www.cnblogs.com/catwin/p/13337144.html

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值