Openstack Horizon二次开发

 系统整体页面:
Openstack Horizon二次开发

1.png (54.53 KB, 下载次数: 2)

下载附件  保存到相册

2014-11-1 17:08 上传




代码结构:
Openstack Horizon二次开发

horizon采用django框架编写(django是一个强大的mvc 框架。具体参考djangobook中文版 http://djangobook.py3k.cn/2.0/。)


左侧面板布局:
Openstack Horizon二次开发

代码:
  1. vim /usr/share/openstack-dashboard/openstack_dashboard/dashboards/admin/dashboard.py
复制代码 Openstack Horizon二次开发


实例列表布局:
Openstack Horizon二次开发

  1. vim /usr/share/openstack-dashboard/openstack_dashboard/dashboards/project/instances/tables.py
复制代码 Openstack Horizon二次开发


上述三个按钮在table_actions中定义。
Openstack Horizon二次开发


上述按钮在row_actions中定义。

第一部分:openstack_dashboard调用流程
接下来以resize instance 为例:
Openstack Horizon二次开发


重点关注下图url链接:
Openstack Horizon二次开发


1、urls.py层代码分析:

所有页面的url链接都由urls.py处理:
  1. vim /usr/share/openstack-dashboard/openstack_dashboard/dashboards/project/instances/urls.py
复制代码 Openstack Horizon二次开发


找到risize对应的url行。调用views.ResizeView.as_view().


2、views.py层代码分析详解--跟进到views层的ResizeView:
  1. #说明resize功能使用workflow工作,下一步详解,请参考:workflow-1.1
  2. workflow_class = project_workflows.ResizeInstance
  3. #执行成功跳转到horizon:project:instances:index链接文件:下一步详解,请参考:模板页面-1.1
  4. success_url = reverse_lazy("horizon:project:instances:index")
复制代码
  1. #这个函数返回的值给context这个字典,这个字典里的值可以在html中取到
  2.     @memoized.memoized_method
  3.     def get_object(self, *args, **kwargs):
  4.         instance_id = self.kwargs['instance_id']
  5.         try:#根据实例id获取实例,下一步详解,下一步api调用流程请参考:“horizon中实例resize的API调用步骤详解“(与之类似)。
  6.             instance = api.nova.server_get(self.request, instance_id)
  7.             flavor_id = instance.flavor['id']
  8.             flavors = self.get_flavors()
  9.             if flavor_id in flavors:
  10.                 instance.flavor_name = flavors[flavor_id].name
  11.             else:
  12.                 flavor = api.nova.flavor_get(self.request, flavor_id)
  13.                 instance.flavor_name = flavor.name
  14.         except Exception:
  15.             redirect = reverse("horizon:project:instances:index")
  16.             msg = _('Unable to retrieve instance details.')
  17.             exceptions.handle(self.request, msg, redirect=redirect)
  18.         return instance
复制代码
  1. #这个函数主要用来填充context字典,该字典可以和对应的html模板传参
  2.     def get_context_data(self, **kwargs):
  3.         context = super(ResizeView, self).get_context_data(**kwargs)
  4.         context["instance_id"] = self.kwargs['instance_id']
  5.         return context
复制代码
  1. #获取flavors list
  2.     @memoized.memoized_method
  3.     def get_flavors(self, *args, **kwargs):
  4.         try:
  5.              #获取数据库中已存在的flavors,下一步api调用流程请参考:“horizon中实例resize的API调用步骤详解“(与之类似)。
  6.             flavors = api.nova.flavor_list(self.request)
  7.             return SortedDict((str(flavor.id), flavor) for flavor in flavors)
  8.         except Exception:
  9.             redirect = reverse("horizon:project:instances:index")
  10.             exceptions.handle(self.request,
  11.                 _('Unable to retrieve flavors.'), redirect=redirect)
复制代码
  1. #获取初始化数据,为对应的表单forms.py提供数据。(譬如下拉框数据如下图1。)
  2.     def get_initial(self):
  3.         initial = super(ResizeView, self).get_initial()
  4.         _object = self.get_object()
  5.         if _object:
  6.             initial.update({'instance_id': self.kwargs['instance_id'],
  7.                 'name': getattr(_object, 'name', None),
  8.                 'old_flavor_id': _object.flavor['id'],
  9.                 'old_flavor_name': getattr(_object, 'flavor_name', ''),
  10.                 'flavors': self.get_flavors()}) #此处调用上处get_flavors函数
  11.         return initial
复制代码
图1:
Openstack Horizon二次开发


1、详解resize功能的workflow机制:
  1. class ResizeView类中:workflow_class = project_workflows.ResizeInstance
  2. vim /usr/share/openstack-dashboard/openstack_dashboard/dashboards/project/instances/workflows/resize_instance.py
复制代码
Openstack Horizon二次开发
  1. #成功与失败的弹出消息及成功之后的跳转url地址。
  2. success_message = _('Scheduled resize of instance "%s".')
  3. failure_message = _('Unable to resize instance "%s".')
  4. success_url = "horizon:project:instances:index"
  5. #完成resize工作流两个步骤:(如下图2)
  6. default_steps = (SetFlavorChoice, create_instance.SetAdvanced)
  7. #格式化状态消息输出
  8.     def format_status_message(self, message):
  9.         return message % self.context.get('name', 'unknown instance')
  10. #完成resize工作流两个步骤:(如下图2)
  11.     @sensitive_variables('context')
  12.     def handle(self, request, context):
  13. #从views.py层中的context字典获取数据
  14.         instance_id = context.get('instance_id', None)
  15.         flavor = context.get('flavor', None)
  16.         disk_config = context.get('disk_config', None)
  17.         try: #页面点击确认resize按钮,调用api resize 实例。本步骤将重点分析。下一步详情,请参考horizon中实例resize的API调用步骤详解:
  18.             api.nova.server_resize(request, instance_id, flavor, disk_config)
  19.             return True
  20.         except Exception:
  21.             exceptions.handle(request)
  22.             return False
复制代码
图2:
Openstack Horizon二次开发


模板页面-1.1:
模板页面文件位置:
  1. vim /usr/share/openstack-dashboard/openstack_dashboard/dashboards/project/instances/templates/instances/index.html
复制代码 Openstack Horizon二次开发

其中%%代表要替换掉的变量(若有疑问自行参考djangobook文档)。
table.render:表示将model层的数据渲染到页面。

horizon中实例resize的API调用步骤详解:
接着上述workflow中resize
  1. api.nova.server_resize(request, instance_id, flavor, disk_config)
复制代码
根据import原则找到api文件:
  1. vim /usr/share/openstack-dashboard/openstack_dashboard/api/__init__.py
复制代码 Openstack Horizon二次开发


此处将base、ceilometer、keystone等 都导入进来了。
跟踪到nova.api代码中:找到server_resize方法:
  1. def server_resize(request, instance_id, flavor, disk_config=None, **kwargs):
  2.     novaclient(request).servers.resize(instance_id, flavor,
  3.                                        disk_config, **kwargs)
复制代码
  1. #拼装client,组装url参数(包括keystone的token,以及调用v1_1、还是v3版本的novaclient参数等等)
  2. def novaclient(request):
  3.     insecure = getattr(settings, 'OPENSTACK_SSL_NO_VERIFY', False)
  4.     cacert = getattr(settings, 'OPENSTACK_SSL_CACERT', None)
  5.     LOG.debug('novaclient connection created using token "%s" and url "%s"' %
  6.               (request.user.token.id, base.url_for(request, 'compute')))
  7. #根据返回的c知道接下来调用的是novaclient代码:因此上述方法server_resize调用novaclient中server.py中的resize方法
复制代码

下述流程则参考以下的novaclientAPI调用流程。
  1.     c = nova_client.Client(request.user.username,
  2.                            request.user.token.id,
  3.                            project_id=request.user.tenant_id,
  4.                            auth_url=base.url_for(request, 'compute'),
  5.                            insecure=insecure,
  6.                            cacert=cacert,
  7.                            http_log_debug=settings.DEBUG)
  8.     c.client.auth_token = request.user.token.id
  9.     c.client.management_url = base.url_for(request, 'compute')
  10.     return c
复制代码

第二部分:novaclientAPI调用流程
从dashboard代码入口开始:
  1. def server_resize(request, instance_id, flavor, disk_config=None, **kwargs):
  2.     novaclient(request).servers.resize(instance_id, flavor,
  3.                                        disk_config, **kwargs)
复制代码

下图为novaclient的代码结构:
接着调用novaclient模块中v1_1里面的services.py文件resize方法。
Openstack Horizon二次开发

manage里面的resize方法:
Openstack Horizon二次开发



调用action方法:
Openstack Horizon二次开发


#下面两句代码拼接一个url地址
  1. url = '/servers/%s/action' % base.getid(server)
  2.         return self.api.client.post(url, body=body)
  3. #发送url,通过wsgi调用nova代码。
 
上一篇:8.21


下一篇:PowerManagerService第三讲之灭屏