实现功能:

增加一个计算节点列表,并连接到该计算节点的所有虚拟机列表

 因为目前没有取得计算几点的api。所以这个功能目前先按照实例列表中过滤存在实例的主机列表。 点击主机名称进入查找该主机下的所有实例列表

 

1.增加菜单(主机)

参照 

horizon源码修改——加菜单和菜单汉化

 

2.控制页面上内容显示(只显示主机列)

tables.py

增加一个类:主机列表类

class SyspanelHostsTable(tables.DataTable):
     tenant = tables.Column("tenant_name", link="horizon:nova:instances_and_volumes:" \
                              "instances:detail",
                              verbose_name=_("Tenant"))
     host = tables.Column("OS-EXT-SRV-ATTR:host",#link="horizon:nova:instances_and_volumes:instances:detail",
                         #link="instance",
                         link="horizon:syspanel:hosts:instance",
                         verbose_name=_("Host"),
                         classes=('nowrap-col',))    name = tables.Column("name", link="horizon:nova:instances_and_volumes:" \
                          "instances:detail",
                          verbose_name=_("Instance Name"))    class Meta:
         name = "instances"
         verbose_name = _("Instances")
         columns = ("host",)

 

 

 

如果控制显示列数有2个方法

1.删除这里面的某一列

                    

如虚拟机列表只显示

class SyspanelHostsTable(tables.DataTable):
     tenant = tables.Column("tenant_name", verbose_name=_("Tenant"))
     host = tables.Column("OS-EXT-SRV-ATTR:host",
                         verbose_name=_("Host"),
                         classes=('nowrap-col',)
                         , link = "horizon:syspanel:hosts:index")
     name = tables.Column("name", link="horizon:nova:instances_and_volumes:" \
                          "instances:detail",
                          verbose_name=_("Instance Name"))

这里可以删除name和tenant ,不显示name  也可以用下面的方法columns = ("host", "tenant")

 

2.在Table类的class Meta:

增加columns属性 

class Meta:
         name = "instances"
         verbose_name = _("Instances")
         multi_select = True
         columns = ("host",)#columns = ("host", "tenant")

注意:只显示一列的时候,括号里边必须带逗号(,)

 

 multi_select = False #True  列表前面的多选按钮是否显示

  

列表如果连接到一个地址,点击主机项跳转到该主机下所有的实例列表

host = tables.Column("OS-EXT-SRV-ATTR:host
                        link="horizon:syspanel:hosts:instance",
                        verbose_name=_("Host"),
                        classes=('nowrap-col',))

 

                       

 注意“连接参数好像只能是instanceid (主键为传递参数,以位置为传递参数的方法正在找)

上面link要写全,否则不能跟上参数,不能只写link = "instance"

 

 3.URLConf

urls.py

from 增加AdminHostsView

from .views import DetailView, AdminIndexView ,AdminHostsView

 

INSTANCES = r'^(?P<instance_id>[^/]+)/%s$'

修改indexurl为跳转到主机列表页

url(r'^$', AdminHostsView.as_view(), name='index'),

 

增加下面内容,(主键为传递参数,以位置为传递参数的方法正在找)

url(INSTANCES % 'instance', AdminIndexView.as_view(), name='instance'),

 


 4.nova.py


主机列表视图需要取得所有的实例列表,然后每个主机取一条。这样过滤出存在实例的主机列表


注意,api返回的实例数据格式为[<horizon.api.nova.Server object at 0x7f9d85602c10>, <horizon.api.nova.Server object at 0x7f9d85602b10>]


要想从中取出host名称,需要在api的Server了增加一个属性def host_name(self):


 


修改horizon/api/nova.py


 Server类如下

查看所有KVM虚拟机配置 查看虚拟机列表_Server

 

 

 

 

class Server(APIResourceWrapper):

增加一个属性:host_name

 

@property
 def host_name(self):
        return getattr(self, 'OS-EXT-SRV-ATTR:host', "")

这样views.py中就可以直接使用host_name属性了。

 

因为还有一个需求就是实例列表加入分页,所以在nova.py

server_list中增加了分页。

如果过滤主机显然需要取全部数据

于是在nova.py中增加方法server_list_all 该方法复制最原始的server_list方法。

 

5.views.py

增加

from horizon.dashboards.syspanel.hosts.tables import SyspanelInstancesTable
 from horizon.dashboards.syspanel.hosts.tables import SyspanelHostsTable 
class  AdminHostsView(tables.DataTableView):
     table_class = SyspanelHostsTable
     template_name = 'syspanel/hosts/index.html'  中过滤主机的实现方法
def get_data(self):
         instances = []
         instances2 = []
         try:
             instances = api.nova.server_list_all(self.request, all_tenants=True)
         except:
             exceptions.handle(self.request,
                             _('Unable to retrieve instance list.'))
         
         if instances:
             for inst in instances:
                 hflag = 0
                 if len(instances2)==0:
                     instances2.append(inst)
                 else:
                     for inst2 in instances2:
                         if inst.host_name == inst2.host_name:
                             hflag = 1
                     if hflag ==0:
                         instances2.append(inst)        #LOG.error(instances2)
         return instances2 
 
 
点击一个主机名字进入实例列表页面实现
class AdminIndexView(tables.DataTableView):
     table_class = SyspanelInstancesTable
     template_name = 'syspanel/hosts/index.html' 
def get_data(self):修改为get_data(self , *args, **kwargs):
 
def get_data(self , *args, **kwargs):
         instances = []
         search_opts = {}
         instance_id = self.kwargs["instance_id"]
         if not hasattr(self, "instance"):
             instance = api.server_get(self.request,instance_id)        search_opts["host"] =instance.host_name
       
         try:
             instances = api.nova.server_list(self.request, search_opts,  all_tenants=True)
         except:
             exceptions.handle(self.request,
                               _('Unable to retrieve instance list.'))
         if instances:
             # Gather our flavors to correlate against IDs
             try:
                 flavors = api.nova.flavor_list(self.request)
             except:
                 flavors = []
                 msg = _('Unable to retrieve instance size information.')
                 exceptions.handle(self.request, msg)
             # Gather our tenants to correlate against IDs
             try:
                 tenants = api.keystone.tenant_list(self.request, admin=True)
             except:
                 tenants = []
                 msg = _('Unable to retrieve instance tenant information.')
                 exceptions.handle(self.request, msg)            full_flavors = SortedDict([(f.id, f) for f in flavors])
             tenant_dict = SortedDict([(t.id, t) for t in tenants])
             for inst in instances:
                 inst.full_flavor = full_flavors.get(inst.flavor["id"], None)
                 tenant = tenant_dict.get(inst.tenant_id, None)
                 inst.tenant_name = getattr(tenant, "name", None)    return instances

6.页面文件

horizon/dashboards/syspanel/templates/syspanel/hosts
index.html
{% extends 'syspanel/base.html' %}
 {% load i18n %}
 {% block title %}Instance {% endblock %}{% block page_header %}
   {% url horizon:syspanel:hosts:index as refresh_link %}
   {# to make searchable false, just remove it from the include statement #}
   {% include "horizon/common/_page_header.html" with title=_("Instances") refresh_link=refresh_link searchable="true" %}
 {% endblock page_header %}{% block syspanel_main %}
   {{ table.render}}
 {% endblock %} 
 
hosts.html
 {% extends 'syspanel/base.html' %}
 {% load i18n %}
 {% block title %}Host{% endblock %}{% block page_header %}
   {% url horizon:syspanel:hosts:index as refresh_link %}
   {# to make searchable false, just remove it from the include statement #}
   {% include "horizon/common/_page_header.html" with title=_("Host") refresh_link=refresh_link searchable="true" %}
 {% endblock page_header %}{% block syspanel_main %}
   {{ table.render}}
 {% endblock %}