OpenStack新手开发指南

更新时间:2024-05-12 08:49:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

OpenStack新手开发指南

目录

1、nova源码架构介绍2 1.1、源码的获取2 1.2、开发环境的搭建2 1.3、nova模块调用介绍6 1.4、nova源码模块功能介绍7 2、数据库表结构的扩展8 2.1、nova表结构的扩展8

2.2、keystone表结构的扩展10 3、resetful接口服务的扩展12

3.1、nova数据库调用接口服务的扩展12 3.2、compute接口的扩展17

3.3、keystone接口服务的扩展20

3.4、基于openstack服务、配置架构自定义服务模块21 4、dashboard源码介绍25 4.1 horizon代码模块介绍26 4.2 中文化的功能实现26 4.3 页面按钮的添加27

4.4 列表中下拉菜单的添加29 4.5 列表中文字链接的添加29

1、nova源码架构介绍 1.1、源码的获取

openstack的源码可以从安装好的openstack环境上直接copy下来使用,也可以从官网下载(红帽地址:http://repos.fedorapeople.org/repos/openstack/),ubuntu环境下openstack的源码目录为:/usr/share/pyshared/,这里面的源码安装好后会被外链到

/usr/lib/python2.7/dist-packages/,这是python2.7以后的版本的做法,所有的python项目都会采取这种存储方式;centos环境下openstack一般会安装python2.6的环境,所以openstack的源码存储在/usr/lib/python2.6/site-packages/。

1.2、开发环境的搭建

第一步、从官网下载python安装包(http://www.python.org/getit/),如果是openstack的环境下开发,可以忽略这一步,因为安装openstack的时候已经自动安装了python环境。 第二步、然后安装开发python程序的IDE,python的程序一般使用PyDev作为开发工具,它可以被集成到eclipse和aptana等IDE中。PyDev的下载地址:

http://pydev.org/download.html,aptana的下载地址:http://aptana.org/,当前发布的是aptana3.0,默认已经集成了PyDev。当前我使用的是aptana,由于3.0使用的面板背景色是黑色的,我又习惯使用2.0的风格怎么办那,3.0有添加了一个颜色模板的菜单,选择一下“Aptana Studio 2.x”就可以了,如下图。

第三步、导入openstack的项目,打开IED,在左边的面板空白处右键,左键点击“import”, 如下图:

从弹出的窗口从选择“Existing Folder As New Project”,导入一个文件夹作为一个工程,如下图所示:

然后选择一个openstack项目,比如我当前选择了nova文件夹,起一个工程名,只要自己好记就行,下边的单选框可以不用选,点击完成就行了,如下图:

导入进来的nova目录结构如下图:

1.3、nova模块调用介绍

nova-api :起到Cloud Controller的作用,主要为所有的API查询提供了一个接口(比如Openstack API ,EC2 API),引发多数业务流程的活动(如运行一个实例),并实施一些政策(主要是配额检查)。

nova-schedule :接受一个消息队列的虚拟实例请求,通过算法决定该请求应该在那台主机上运行,这个算法可以由我们指定。即起到调度器(Scheduler)的作用.

nova-compute:是一个非常重要的守护进程,负责创建和终止虚拟机实例,即管理着虚拟机实例的生命周期。该模块内部非常复杂,基本原理是简单的,就是接受来自队列的动作然后执行一些列的系统操作(如启动一个KVM实例),并且更新数据库的状态。 nova-network :该守护进程跟nova-compute and nova-volume 2个模块的功能是相似的。接受来自队列的任务,然后执行相应的任务对网络进行操作(比如:安装网桥接口和改变iptable规则)

Queue:为各个模块之间的通信提供起到一个集线器的作用,即数据交换中心。目前是采用RabbitMQ ,理论上是可以采用任何的基于python ampqlib的AMPQ message queue。 SQL database: 存储云基础设施构建时和运行时状态。包括可用的实例类型,正在使用的实例类型,可用的网络和项目。理论上,OpenStack Compute是支持所有基于 SQL-Alchemy的数据库,但目前广泛使用的数据库主要是Sqlite3,Mysql,PostgreSQL。

Glance:该项目独立于Openstack Compute,起到镜像的作用。在该项目中,主要包括三个部分: glance-api, glance-registry and 镜像存储。Glance-api接受API调用,

glance-registry存储和检索镜像的元数据。镜像存储Image blobs。存储可以选择不同的存储方案,比如用Swift实现存储。

Dashboard:该项目是一个可选的项目,主要是为开发者等提供API。

1.4、nova源码模块功能介绍

2、数据库表结构的扩展 2.1、nova表结构的扩展

第一步、创建表的数据库结构,创建表结构的文件存在于目录nova.db.sqlalchemy.migrate_repo.versions,当执行nova-manage db sync命令时就会按照这个目录下文件开头的序列号顺序执行。添加表时只需要实现一个类似的文件,把名字的开头命名为最大序列值加1。比如我要创建一张表,表名为:domains,在这个versions下创建一个084_add_domains.py的文件,文件内容如下 #-*- coding: utf-8 -*-

from sqlalchemy import Boolean, Column, DateTime, Integer from sqlalchemy import MetaData, String, Table from nova import log as logging

LOG = logging.getLogger(__name__)

def upgrade(migrate_engine): ''' 创建表 '''

meta = MetaData()

meta.bind = migrate_engine #生成创建表sql语句

domains = Table('domains', meta,

Column('id', Integer(), primary_key=True, nullable=False), Column('name',

String(length=255, convert_unicode=False, assert_unicode=None,

unicode_error=None, _warn_on_bytestring=False)), Column('ttl', Integer()), Column('rdtype',

String(length=255, convert_unicode=False, assert_unicode=None,

unicode_error=None, _warn_on_bytestring=False)), Column('rdata',

String(length=255, convert_unicode=False, assert_unicode=None,

unicode_error=None, _warn_on_bytestring=False)), Column('project_id',

String(length=255, convert_unicode=False, assert_unicode=None,

unicode_error=None, _warn_on_bytestring=False)), Column('created_at', DateTime(timezone=False)), Column('updated_at', DateTime(timezone=False)), mysql_engine='InnoDB' ) try:

domains.create() except Exception, e:

LOG.exception('Exception while creating domains table, error' % str(e)) raise

#构造初始化信息

DOMAINDS = {

'NS': dict(name='test.com', rdata='ns0.test.com.', rdtype='NS', ttl=86400),

'SOA': dict(name='test.com', rdata='test.com. www.test.com. 200309181 28800 7200 86400 28800', rdtype='SOA', ttl=86400)} try:

#逐行插入初始化信息

domain_insert = domains.insert()

for name, values in DOMAINDS.iteritems():

domain_insert.execute({'name': values[\ 'rdata': values[\ 'rdtype': values[\ 'ttl': values[\ except Exception, e:

LOG.exception('Exception while seeding domains table, error: %s' % str(e)) raise

def downgrade(migrate_engine): ''' 删除表 ''' meta = MetaData()

meta.bind = migrate_engine

domains = Table('domains', meta, autoload=True) domains.drop()

第二步、生成表结构的模型,nova的表对象模型存在于

nova.db.sqlalchemy.migrate_repo.models.py文件中,需要在这里面添加一个实现类,位置无所谓,但一般新添加的都放到文件的最末尾,这里我添加一个domains的模型类,代码如下:

class Domain(BASE, PhysicalBase): \虚拟机主机名 \

__tablename__ = \

id = Column(Integer, primary_key=True) name = Column(String(255)) ttl = Column(Integer)

rdtype = Column(String(255)) rdata = Column(String(255)) project_id = Column(String(255))

第三步、实现表查询,因为nova使用的事sqlalchemy,所以查询只需要按照它的规则构造就行,数据库查询的方法都在nova.db.sqlalchemy.api.py文件中,可以实现增删改查功能,下边我实现一个创建功能的语句,代码如下:

@require_admin_context

def domain_create(context, values):

if model_query(context, models.Domain, read_deleted=\

filter(and_(models.Domain.name == values['name'], models.Domain.rdata == values['rdata'])).\\

count() == 0:

domain = models.Domain() domain.update(values)

domain.project_id = context.project_id domain.save() return domain else:

return None

第四步、添加一个表查询语句的封装结构,为了安全起见,nova的其它模块不直接调用执行数据库查询的方法,而是调用一个上层封装的方法。在nova.db.api.py文件中添加一行调用就行,nova的其它模块调用数据库接口都是引用的这个文件,代码如下: def domain_create(context, values):

return IMPL.domain_create(context, values)

2.2、keystone表结构的扩展

Keystone的表结构扩展相对容易,虽然数据库中间件使用的也是sqlalchemy,但是在

keystone中只需要在keystone.identity.backends.sql.py文件中实现一个抽象类就可以,使用命令执行keystone-manage db_sync后表结构就可以正常创建。

第一步,构建表结构,现在我添加一个表tenant_key,实现的代码如下: class TenantKey(sql.ModelBase, sql.DictBase): __tablename__ = 'tenant_key'

id = sql.Column(sql.String(64), primary_key=True) tenant_id = sql.Column(sql.String(64), unique=True) extra = sql.Column(sql.JsonBlob())

@classmethod

def from_dict(cls, tenant_dict):

# shove any non-indexed properties into extra extra = {}

for k, v in tenant_dict.copy().iteritems(): # TODO(termie): infer this somehow if k not in ['id', 'tenant_id', 'extra']: extra[k] = tenant_dict.pop(k)

tenant_dict['extra'] = extra return cls(**tenant_dict)

def to_dict(self):

extra_copy = copy.deepcopy(self.extra) extra_copy['id'] = self.id

extra_copy['tenant_id'] = self.tenant_id

return extra_copy

keystone中每个表都需要有extra这个字段,内容最多两个元素的字典数据,在接口调用时会把字典中的键值构造成表的字段,对应值的数据类型也会原封不变的恢复。比如一条记录extra的值为:{“addresses”: [“192.168.71.101”, “192.168.71.102”]},值是一个列表,存到数据库是原样存储的,接口返回时会还会被构造为一个列表。

每个实体类都有from_dict、to_dict两个方法,这个是用来接口和数据库进行数据转换时用的函数。

第二步,添加查询语句,查询语句需要在下边的Identity类中添加,下边是实现的创建tenant_key记录的代码:

def create_tenant_key(self, tenant_id): session = self.get_session() with session.begin():

tenant_key_ref = TenantKey()

tenant_key_ref.id = uuid.uuid4().hex tenant_key_ref.tenant_id = tenant_id

tenant_key_ref.extra = {'public_key': public_key} session.add(tenant_key_ref)

session.flush()

return tenant_key_ref.to_dict()

第三步,添加调用封装,和nova的类似,需要加一层封装,这里的封装更像是一个java中的接口方法的添加,在keystone.identity.core.py的Driver添加一个方法,以供上层模块调用数据库接口,如果只是在backends.sql.py中内部调用的话,此步可以省略。

3、resetful接口服务的扩展

3.1、nova数据库调用接口服务的扩展

Openstack的所有模块之间的交互都是采用reset接口的方式实现的,所以掌握模块reset接口的扩展至关重要,而接口的扩展中数据库调用的接口相对容易实现。

Nova的接口服务都是在nova.api.openstack下边实现,而对于扩展或者发行版来说,

openstack的版本升级是很大的一个隐患,所以接口的扩展一般都独立写成一个文件,或者一个单独的类、方法。

nova.api.openstack下边有两个模块,一个是compute这个主要是虚拟机和宿主机相关的接口实现,volume是快存储相关接口的实现。

第一步,实现接口的数据库调用模块,现在实现一个宿主机相关的接口文件,在nova.api.openstack.compute下边添加一个文件:machines.py,实现一个查询所有machine实例列表接口,代码如下: #-*- coding:utf-8 -*-

import webob.exc

from nova.api.openstack import common

from nova.api.openstack.compute.views import machines as views_machines from nova.api.openstack import wsgi from nova.api.openstack import xmlutil from nova import exception from nova import flags from nova import db

from nova import log as logging

LOG = logging.getLogger(__name__) FLAGS = flags.FLAGS

def make_machine(elem, detailed=False): elem.set('floating_ip') elem.set('name') elem.set('id')

if detailed:

elem.set('updated')

elem.set('created')

class MinimalMachinesTemplate(xmlutil.TemplateBuilder): def construct(self):

root = xmlutil.TemplateElement('machines')

elem = xmlutil.SubTemplateElement(root, 'machine', selector='machines') make_machine(elem)

xmlutil.make_links(root, 'machines_links')

return xmlutil.MasterTemplate(root, 1, nsmap=machine_nsmap)

class MachinesTemplate(xmlutil.TemplateBuilder): def construct(self):

root = xmlutil.TemplateElement('machines')

elem = xmlutil.SubTemplateElement(root, 'machine', selector='machines') make_machine(elem, detailed=True)

return xmlutil.MasterTemplate(root, 1, nsmap=machine_nsmap)

class Controller(wsgi.Controller):

_view_builder_class = views_machines.ViewBuilder

def __init__(self, **kwargs):

super(Controller, self).__init__(**kwargs)

@wsgi.serializers(xml=MinimalMachinesTemplate) def index(self, req):

\获取machines所有实例名字信息 \ context = req.environ['nova.context']

try:

all_machines = db.machine_get_all(context) except exception.Invalid as e:

raise webob.exc.HTTPBadRequest(explanation=str(e)) return self._view_builder.index(req, all_machines)

@wsgi.serializers(xml=MachinesTemplate) def detail(self, req):

\获取machine所有列表的详细字段信息 \

context = req.environ['nova.context'] try:

all_machines = db.machine_get_all(context) except exception.Invalid as e:

raise webob.exc.HTTPBadRequest(explanation=str(e))

return self._view_builder.detail(req, all_machines)

def create_resource():

return wsgi.Resource(Controller())

MinimalMachinesTemplate、MachinesTemplate两个类用来进行接口数据输出时json格式的转化,先使用xml定义json的模板。 Index方法将在默认调用时显示,detail显示详细的数据参数,调用时在url的最后添加/detail就行。

req.environ['nova.context']用来获取请求头中的用户信息,只有符合权限的用户才能调用相应接口,返回对应用户的数据信息。

machine_get_all是nova.db.api.py中的方法,从文件最上边的模块导入中可以看到。 views_machines.ViewBuilder用来在接口返回时向模板填充数据

第二步,实现接口调用后的展示部分, 在nova.api.openstack.compute.views下添加machines.py文件,代码如下: #-*- coding:utf-8 -*-

import os.path

from nova.api.openstack import common from nova import flags from nova import utils

FLAGS = flags.FLAGS

class ViewBuilder(common.ViewBuilder):

_collection_name = \

def basic(self, request, machine): return {

\

\

\ \

\ }, }

def show(self, request, machine): machine2dict = {

\

'name': machine.get(\domain_name\

'floating_ip': machine.get(\

\ \ \ }

return dict(machine=machine2dict)

def detail(self, request, machines):

list_func = self.show

return self._list_view(list_func, request, machines)

def index(self, request, machines): list_func = self.basic

return self._list_view(list_func, request, machines)

def _list_view(self, list_func, request, machines):

machine_list = [list_func(request, machine)[\ machines_links = self._get_collection_links(request, machines) machines_dict = dict(machines=machine_list)

if machines_links:

machines_dict[\

return machines_dict

def _get_links(self, request, identifier):

\ return [{

\

\ }, {

\

\

@staticmethod

def _format_time(date_string):

\ if date_string is not None:

return date_string.strftime('%Y-%m-%d %H:%M:%S')

这个文件就属于web框架中MVC中的页面展示部分

第三步、实现访问地址和控制器的路由配置,在nova.api.openstack.compute.__init__.py文件中,添加如下代码:

from nova.api.openstack.compute import machines

self.resources['machines'] = machines.create_resource() mapper.resource(\controller=self.resources['machines'], collection={'detail': 'GET'})

第四步、重启nova-api,执行/etc/init.d/nova-api restart

第五步、调试接口是否可以正常使用,执行命令:curl -X GET -H

\http://192.168.70.201:8774/v1.1/ ... 178cd1079d/machines,将会调用nova.api.openstack.compute.machines.py的index方法

curl -X GET -H

\http://192.168.70.201:8774/v1.1/ ... 79d/machines/detail 将会调用nova.api.openstack.compute.machines.py的detail方法,正常情况下将会返回数据库中的信息

第六步、编写python-novaclient客户端程序,写好的api接口怎么让horizon使用哪,这就需要python的客户端帮忙了,这部分的代码相对比较简单。找到novaclient所在的目录,python2.6可以在/usr/lib/python2.6/site-packages/novaclient中找到源码,在novaclient.v1.1目录下添加machines.py文件,代码如下: #-*- coding:utf-8 -*-

from novaclient import base

class Machine(base.Resource): HUMAN_ID = True

def __repr__(self):

return \

class MachineManager(base.ManagerWithFind): \

Manage :class:`machine` resources. \

resource_class = Machine

def list(self, detailed=True): if detailed is True:

return self._list(\ else:

return self._list(\

然后在novaclient.v1.1.client.py中导入machines文件,from novaclient.v1_1 import machines的__init__构造函数中添加:self.machines = machines.MachineManager(self) 第七步,horizon的接口调用都会在进行一次封装,在horizon.api.nova.py中添加代码如下: def machine_list(request):

return novaclient(request).machines.list()

现在为止一个完整的nova接口就算完成了,剩下的就是horizon代码里面的调用,这个下边会将。

3.2、compute接口的扩展

Compute的接口实现是openstack当中层级最多的,因为他是属于多节点的调用,用到了rabbitMQ任务调度模块,底层又调用了libvirt接口,所以实现起来可能有点麻烦,但是理清了各个文件的职能,那就只剩下往里面填充代码了,下边是一个虚拟机操作的一个接口调用流程图:

现在我按照这个流程实现一个虚拟机快照功能,接口一般从底层往

上写,这样可以一级级调试,代码写完就可以运行,避免最后代码都写完了,一旦出错就不知道到底是哪一层出的问题。

第一步,编写快照功能的底层实现,在nova.virt.libvirt.connection.py的LibvirtConnection类中实现一个快照的方法,代码如下:

@exception.wrap_exception()

def create_vm_snapshot(self, context, instance, snapshot_name, snapshot_description): try:

#获取虚拟机实例

virt_dom = self._lookup_by_name(instance['name']) except exception.InstanceNotFound:

raise exception.InstanceNotRunning()

try:

xmldesc = '\\ %s\\

%s\\ \\

%s\\ \\

' % (snapshot_name, snapshot_description, instance['uuid']) LOG.info('snapshot xml: %s' % xmldesc)

#创建虚拟机快照

snapshot_dom = virt_dom.snapshotCreateXML(xmldesc.encode('utf-8', 'ignore'), 0)

if snapshot_dom is None:

LOG.error('create instance %s snapshot %s is error' % (instance['name'], snapshot_name)) else:

LOG.info('create snapshot %s is successful' % snapshot_name) except Exception, e:

LOG.error('create snapshot is error: %s' % str(e))

raise exception.CreateSnapshotFailed(snapshot_name=snapshot_name)

第二步,在nova.compute.manager.py中构造调用底层实现的参数,manager.py这个文件在每个compute节点都会运行,所以如果多节点的环境,进行代码更新时要全部更新,实现代码如下:

@exception.wrap_exception(notifier=notifier, publisher_id=publisher_id()) @checks_instance_lock @wrap_instance_fault

def create_vm_snapshot(self, context, instance_uuid, snapshot_name, description): \ context = context.elevated()

instance_ref = self.db.instance_get_by_uuid(context, instance_uuid)

current_vm_state = instance_ref['vm_state'] self._instance_update(context,

instance_ref['id'],

task_state=task_states.SNAPSHOTTING, vm_state=vm_states.SNAPSHOTTING)

LOG.audit(_(\ self._notify_about_instance_usage(instance_ref, \

try:

self.driver.create_vm_snapshot(context, instance_ref, snapshot_name, description) finally:

self._instance_update(context, instance_ref['id'], task_state=None, vm_state=current_vm_state)

self._notify_about_instance_usage(instance_ref, \

第三步、完成快照功能的接口封装,在nova.compute.api.py的API类中实现方法的封装,代码如下:

def create_vm_snapshot(self, context, instance, snapshot_name, description): params = {'snapshot_name': snapshot_name, 'description': description}

self._cast_compute_message('create_vm_snapshot', context, instance, params=params) 以下的工作就是nova.api.openstack.compute层以上的工作了,3.1章节已经讲过,这里就不在描述。nova其它模块的接口实现流程类似,实现方式也是类似的,可以参考compute接口去实现。

3.3、keystone接口服务的扩展 Keystone接口扩展相对容易,一是因为底层主要是调用数据库,二是它不涉及多节点架构。在2.2章节keystone表结构扩展时,创建了一个tenant_key的表,下面就实现一个获取表数据实例的接口。

第一步、实现一个表查询接口,在keystone.identity.core.py的Driver类中添加一个抽象接口,代码如下:

def get_tenant_key(self, tenant_id): raise exception.NotImplemented()

传递一个tenant_id参数用来获取一个对象实例

第二步、在keystone.identity.backends.sql.py的Identity类中添加sql对象查询实现,代码如下:

def get_tenant_key(self, tenant_id): session = self.get_session()

tenant_key_ref = session.query(TenantKey).filter_by(tenant_id=tenant_id).first() if not tenant_key_ref: return

return tenant_key_ref.to_dict()

第三步、实现服务接口的调用封装,在keystone.identity.core.py的TenantController类中添加一个方法,代码如下:

def get_tenant_key(self, context, tenant_id): self.assert_admin(context)

tenant_key = self.identity_api.get_tenant_key(context, tenant_id) return {'tenant_key': tenant_key} 第四步、添加接口路由匹配规则,在keystone.identity.core.py的AdminRouter,add_routes方法中,添加如下代码:

mapper.connect('/tenant_keys/{tenant_id}', controller=tenant_controller, action='get_tenant_key',

conditions=dict(method=['GET']))

第五步、验证接口的可用性,执行命令curl -X GET -H

\

\http://192.168.70.201:35357/v2.0/tenant_keys/8a9b447e1f4e466ab3cc5557110e0fed,如果可以正常返回数据库中对应的数据,服务端的接口就算可以用了,剩下的工作和novaclient的做法类似,可以参考novaclient的实现来扩展keystoneclient的接口。

3.4、基于openstack服务、配置架构自定义服务模块

使用openstack中已有的代码,稍加改动就可以实现一个服务架构模块。这部分改动比较凌乱,下面讲的不能完全涵盖要做的工作,剩下的都是些python相关的代码调整,需要有一定的python基础的人自己解决。

做这个工作之前,我研究了nova、keystone、swift、glance的服务代码,发现nova部分要整合多个模块(nova-compute、nova-network、nova-volume等),架构比较复杂,keystone、swift和本身的业务集成太紧密,耦合度太强,不好分离。Glance的服务模块相对容易分离,本身glance提供的接口也不太多,代码的研究也很容易。这几个模块的服务提供机制,最底层都是一样的基于一个wsgi.py模块,里面的内容稍微有点差异,多的是在上层的封装上有些不同,下面我们讲怎么基于glance的服务提供代码,构造自己的服务模块架构。 第一步、拷贝glance相关代码到自己的模块根目录中,创建一个根目录,我这里叫“monitor”,自己的监控模块,拷贝glance. __init__.py、glance. vcsversion.py、glance. version.py、glance.api、glance.common到monitor文件夹下。

第二步、删除不相关的文件,上一步拷贝的monitor.api、monitor.common中有些文件是不需要的,也有些是glance用到的,都要清除掉。删除monitor.api.middleware、monitor.api. cached_images.py、monitor.api.policy.py、monitor.api.v1.filters.py、monitor.api.v1.images.py、monitor.api.v1.members.py、monitor.api.common.animation.py、monitor.api.common. crypt.py、monitor.api.common. policy.py。

第三步、修改源码中的包引用代码,把from glance 改为 from monitor,删除不存在的包引用,删除相关的代码调用。

第四步、拷贝相关配置、启动脚本,拷贝/etc/glance/glance-api.conf内容到

monitor.etc.monitor. monitor-api.conf,删除不相关的配置,修改bind_port的端口为9009(根据自己机器上的端口划分分配),下面是必须的配置项: [DEFAULT]

# Show more verbose log output (sets INFO log level output) verbose = True

# Show debugging output in logs (sets DEBUG log level output) debug = True

# Address to bind the API server bind_host = 0.0.0.0

# Port the bind the API server to bind_port = 9009

# Log to this file. Make sure you do not set the same log # file for both the API and registry servers! log_file = /var/log/monitor/api.log

# Send logs to syslog (/dev/log) instead of to file specified by `log_file` use_syslog = False

拷贝/etc/glance/ glance-api-paste.ini内容到monitor.etc.monitor. monitor-api-paste.ini,删除不相关的配置,在keystone中创建monitor账户,修改admin_user的值为monitor,正确的配置项如下:

[pipeline:monitor-api]

pipeline = versionnegotiation authtoken context apiv1app

[app:apiv1app]

paste.app_factory = monitor.common.wsgi:app_factory monitor.app_factory = monitor.api.v1.router:API

[filter:versionnegotiation]

paste.filter_factory = monitor.common.wsgi:filter_factory

monitor.filter_factory =

monitor.api.middleware.version_negotiation:VersionNegotiationFilter

[filter:context]

paste.filter_factory = monitor.common.wsgi:filter_factory

monitor.filter_factory = monitor.common.context:ContextMiddleware

[filter:authtoken]

paste.filter_factory = keystone.middleware.auth_token:filter_factory service_host = control.n.glodon.org service_port = 5000 service_protocol = http

auth_host = control.n.glodon.org auth_port = 35357

auth_protocol = http

auth_uri = http://control.n.glodon.org:5000/ admin_tenant_name = tenant admin_user = monitor admin_password = service

拷贝/usr/bin/glance-api内容到monitor.usr.bin.monitor-api文件,修改后的内容如下: #!/usr/bin/python

\

Monitor API Server \

action_past = _(\

data_type_singular = _(\ data_type_plural = _(\ classes = ('btn-danger', 'btn-reboot')

def allowed(self, request, instance=None):

return instance.status in ACTIVE_STATES or instance.status == 'SHUTOFF'

def action(self, request, obj_id):

api.server_reboot(request, obj_id)

第二步、在列表中添加按钮,编辑tables.py文件的ImagesTable内部类的table_actions属性。

4.4 列表中下拉菜单的添加

首先要实现一个有效的链接地址,然后添加一个按钮模板,这部分操作和上边讲的链接按钮一样的,最后在tables.py的row_actions中将这个按钮名添加进去就行了。

4.5 列表中文字链接的添加 首先实现一个有效的链接地址,然后在tables.py对应实例的属性中添加这个链接地址即可,下边是虚拟机的一个链接地址代码:

class InstancesTable(tables.DataTable):

name = tables.Column(\ \ verbose_name=_(\

本文来源:https://www.bwwdw.com/article/h93g.html

Top