目录

一.novnc简介

二.openstack中的novnc工作流程

三.源码分析


一.novnc简介

noVNC是一个支持HTML5的VNC客户端,主要作用就是与远端的vnc server进行互通,从而实现对于远端主机的控制。说白了,我们可以通过VNC客户端或者支持HTML5的浏览器访问远端安装了vnc server的服务器桌面从而进行控制。

但是vnc server发送的数据都是基于TCP之上的,而novnc处理的数据都是基于WebSocket之上的数据,所以vnc客户端无法直接与vnc server进行通讯,因此中间加入了一个代理服务器:WebSockify来实现WebSockify和TCP数据之间的转换。

二.openstack中的novnc工作流程

三.源码分析

a. 用户点击某一个虚拟机的console,请求访问通过该虚拟机的id访问该虚拟机的页面。

b. 浏览器向nova-api发送访问请求获得该虚拟机的url。

c. nova-api调用/nova/api/openstack/compute/remote_consoles.py的get_vnc_consoles()函数。

    def get_vnc_console(self, req, id, body):"""Get text console output."""context = req.environ['nova.context']context.can(rc_policies.BASE_POLICY_NAME)# If type is not supplied or unknown, get_vnc_console below will copeconsole_type = body['os-getVNCConsole'].get('type')instance = common.get_instance(self.compute_api, context, id)try:output = self.compute_api.get_vnc_console(context,instance,console_type)except exception.ConsoleTypeUnavailable as e:raise webob.exc.HTTPBadRequest(explanation=e.format_message())except (exception.InstanceUnknownCell,exception.InstanceNotFound) as e:raise webob.exc.HTTPNotFound(explanation=e.format_message())except exception.InstanceNotReady as e:raise webob.exc.HTTPConflict(explanation=e.format_message())except NotImplementedError:common.raise_feature_not_supported()return {'console': {'type': console_type, 'url': output['url']}}

上一个函数调用/nova/compute/api.py/API/get_vnc_console()函数,该函数再调用/nova/compute/rpcapi.py/ComputeAPI/get_vnc_console()函数向nova-compute进行同步RPC调用。

    def get_vnc_console(self, ctxt, instance, console_type):version = self._ver(ctxt, '4.0')cctxt = self.router.client(ctxt).prepare(server=_compute_host(None, instance), version=version)return cctxt.call(ctxt, 'get_vnc_console',instance=instance, console_type=console_type)

d. nova-compute调用manager.py的get_vnc_console()函数获取该RPC消息,然后调用generate_uuid()函数生成uuid作为token;然后判断如果console_type为novnc,则生成access_url:novncproxy_base_url(nova.conf文件)+token(刚才生成的);接下来,通过驱动driver调用libvirt的get_vnc_console()函数从获取vnc_server的详细配置信息(console:host地址(计算节点连接各个instance的内网ip地址)和端口号port);最后将host,port和access_url连接起来生成connect_info。

/nova/compute/manager.py/ComputeManager/get_vnc_console():

    def get_vnc_console(self, context, console_type, instance):"""Return connection information for a vnc console."""context = context.elevated()LOG.debug("Getting vnc console", instance=instance)token = uuidutils.generate_uuid()if not CONF.vnc.enabled:raise exception.ConsoleTypeUnavailable(console_type=console_type)if console_type == 'novnc':# For essex, novncproxy_base_url must include the full path# including the html file (like http://myhost/vnc_auto.html)access_url = '%s?token=%s' % (CONF.vnc.novncproxy_base_url, token)elif console_type == 'xvpvnc':access_url = '%s?token=%s' % (CONF.vnc.xvpvncproxy_base_url, token)else:raise exception.ConsoleTypeInvalid(console_type=console_type)try:# Retrieve connect info from driver, and then decorate with our# access info tokenconsole = self.driver.get_vnc_console(context, instance)connect_info = console.get_connection_info(token, access_url)except exception.InstanceNotFound:if instance.vm_state != vm_states.BUILDING:raiseraise exception.InstanceNotReady(instance_id=instance.uuid)return connect_info

/nova/virt/libvirt/driver.py/LibvirtDriver/get_vnc_console() :

    def get_vnc_console(self, context, instance):def get_vnc_port_for_instance(instance_name):guest = self._host.get_guest(instance)xml = guest.get_xml_desc()xml_dom = etree.fromstring(xml)graphic = xml_dom.find("./devices/graphics[@type='vnc']")if graphic is not None:return graphic.get('port')# NOTE(rmk): We had VNC consoles enabled but the instance in# question is not actually listening for connections.raise exception.ConsoleTypeUnavailable(console_type='vnc')port = get_vnc_port_for_instance(instance.name)host = CONF.vnc.server_proxyclient_addressreturn ctype.ConsoleVNC(host=host, port=port)

e. nova-api继续调用/nova/compute/api.py/API/get_vnc_console()函数,到目前为止,nova-api已经通过get_vnc_console()函数获得了connect_info,然后再次调用consoleauth的authorize_console()函数,具体实现见后文。

    def get_vnc_console(self, context, instance, console_type):"""Get a url to an instance Console."""connect_info = self.compute_rpcapi.get_vnc_console(context,instance=instance, console_type=console_type)self.consoleauth_rpcapi.authorize_console(context,connect_info['token'], console_type,connect_info['host'], connect_info['port'],connect_info['internal_access_path'], instance.uuid,access_url=connect_info['access_url'])return {'url': connect_info['access_url']}

f. /nova/consoleauth/rpcapi.py/ConsoleAuthAPI/authorize_console()函数,该函数会发送RPC调用给nova-consoleauth服务,该服务继续调用/nova/consoleauth/manager.py/ConsoleAuthManager/ authorize_console()函数处理请求,具体是nova-consoleauth会将instance –> token, token –> connect_info的信息cache起来。

    def authorize_console(self, context, token, console_type, host, port,internal_access_path, instance_uuid,access_url=None):token_dict = {'token': token,'instance_uuid': instance_uuid,'console_type': console_type,'host': host,'port': port,'internal_access_path': internal_access_path,'access_url': access_url,'last_activity_at': time.time()}data = jsonutils.dumps(token_dict)self.mc.set(token.encode('UTF-8'), data)tokens = self._get_tokens_for_instance(instance_uuid)# Remove the expired tokens from cache.token_values = self.mc.get_multi([tok.encode('UTF-8') for tok in tokens])tokens = [name for name, value in zip(tokens, token_values)if value is not None]tokens.append(token)self.mc_instance.set(instance_uuid.encode('UTF-8'),jsonutils.dumps(tokens))LOG.info("Received Token: %(token)s, %(token_dict)s",{'token': token, 'token_dict': token_dict})

g. nova-api会将的access_url返回给浏览器,如:http://192.168.174.10:6082/spice_auto.html?token=2842a8d2-704e-4f00-967b-c4812ea68de5&title=vxlan_instance1(716e9189-fad1-4081-9bc9-aba5dd8da272),浏览器向nova-novncproxy发送这个url,然后该服务会调用/nova/console/websocketproxy.py/TenantSocket/new_websocket_client()函数,具体该函数的实现如下讲解:

h. nova-novncproxy服务发起RPC调用给nova-consoleauth服务,nova-consoleauth服务调用check_token函数,nova-consoleauth服务验证了这个token,将这个instance对应的connect_info返回给nova-novncproxy,最后nova-novncproxy通过connect_info中的host, port等信息,连接compute节点上的VNC Server,从而开始了proxy的工作。

    def new_websocket_client(self):"""Called after a new WebSocket connection has been established."""# Reopen the eventlet hub to make sure we don't share an epoll# fd with parent and/or siblings, which would be badfrom eventlet import hubshubs.use_hub()# The nova expected behavior is to have token# passed to the method GET of the requestparse = urlparse.urlparse(self.path)if parse.scheme not in ('http', 'https'):# From a bug in urlparse in Python < 2.7.4 we cannot support# special schemes (cf: http://bugs.python.org/issue9374)if sys.version_info < (2, 7, 4):raise exception.NovaException(_("We do not support scheme '%s' under Python < 2.7.4, ""please use http or https") % parse.scheme)query = parse.querytoken = urlparse.parse_qs(query).get("token", [""]).pop()if not token:# NoVNC uses it's own convention that forward token# from the request to a cookie header, we should check# also for this behaviorhcookie = self.headers.get('cookie')if hcookie:cookie = Cookie.SimpleCookie()for hcookie_part in hcookie.split(';'):hcookie_part = hcookie_part.lstrip()try:cookie.load(hcookie_part)except Cookie.CookieError:# NOTE(stgleb): Do not print out cookie content# for security reasons.LOG.warning('Found malformed cookie')else:if 'token' in cookie:token = cookie['token'].valuectxt = context.get_admin_context()rpcapi = consoleauth_rpcapi.ConsoleAuthAPI()connect_info = rpcapi.check_token(ctxt, token=token)if not connect_info:raise exception.InvalidToken(token=token)# Verify Originexpected_origin_hostname = self.headers.get('Host')if ':' in expected_origin_hostname:e = expected_origin_hostnameif '[' in e and ']' in e:expected_origin_hostname = e.split(']')[0][1:]else:expected_origin_hostname = e.split(':')[0]expected_origin_hostnames = CONF.console.allowed_originsexpected_origin_hostnames.append(expected_origin_hostname)origin_url = self.headers.get('Origin')# missing origin header indicates non-browser client which is OKif origin_url is not None:origin = urlparse.urlparse(origin_url)origin_hostname = origin.hostnameorigin_scheme = origin.schemeif origin_hostname == '' or origin_scheme == '':detail = _("Origin header not valid.")raise exception.ValidationError(detail=detail)if origin_hostname not in expected_origin_hostnames:detail = _("Origin header does not match this host.")raise exception.ValidationError(detail=detail)if not self.verify_origin_proto(connect_info, origin_scheme):detail = _("Origin header protocol does not match this host.")raise exception.ValidationError(detail=detail)self.msg(_('connect info: %s'), str(connect_info))host = connect_info['host']port = int(connect_info['port'])# Connect to the targetself.msg(_("connecting to: %(host)s:%(port)s") % {'host': host,'port': port})tsock = self.socket(host, port, connect=True)# Handshake as necessaryif connect_info.get('internal_access_path'):tsock.send(encodeutils.safe_encode("CONNECT %s HTTP/1.1\r\n\r\n" %connect_info['internal_access_path']))end_token = "\r\n\r\n"while True:data = tsock.recv(4096, socket.MSG_PEEK)token_loc = data.find(end_token)if token_loc != -1:if data.split("\r\n")[0].find("200") == -1:raise exception.InvalidConnectionInfo()# remove the response from recv buffertsock.recv(token_loc + len(end_token))breakif self.server.security_proxy is not None:tenant_sock = TenantSock(self)try:tsock = self.server.security_proxy.connect(tenant_sock, tsock)except exception.SecurityProxyNegotiationFailed:LOG.exception("Unable to perform security proxying, shutting ""down connection")tenant_sock.close()tsock.shutdown(socket.SHUT_RDWR)tsock.close()raisetenant_sock.finish_up()# Start proxyingtry:self.do_proxy(tsock)except Exception:if tsock:tsock.shutdown(socket.SHUT_RDWR)tsock.close()self.vmsg(_("%(host)s:%(port)s: ""Websocket client or target closed") %{'host': host, 'port': port})raise

openstack 之 novnc流程分析相关推荐

  1. Openstack Nova 源码分析 — 使用 VCDriver 创建 VMware Instance

    目录 目录 前言 流程图 nova-compute vCenter 前言 在上一篇 Openstack Nova 源码分析 - Create instances (nova-conductor阶段) ...

  2. OpenStack nova M Blueprints 分析

    OpenStack nova M Blueprints 分析 OpenStack nova M Blueprints 分析 mitaka-1 mitaka-2 mitaka-3 mitaka-rc1 ...

  3. VLC架构及流程分析

    0x00 前置信息 VLC是一个非常庞大的工程,我从它的架构及流程入手进行分析,涉及到一些很细的概念先搁置一边,日后详细分析. 0x01 源码结构(Android Java相关的暂未分析) # bui ...

  4. 动态执行流程分析和性能瓶颈分析的利器——gperftools的Cpu Profiler

    在<动态执行流程分析和性能瓶颈分析的利器--valgrind的callgrind>中,我们领略了valgrind对流程和性能瓶颈分析的强大能力.本文将介绍拥有相似能力的gperftools ...

  5. 动态执行流程分析和性能瓶颈分析的利器——valgrind的callgrind

    在<内存.性能问题分析的利器--valgrind>一文中我们简单介绍了下valgrind工具集,本文将使用callgrind工具进行动态执行流程分析和性能瓶颈分析.(转载请指明出于brea ...

  6. 解析并符号 读取dll_Spring IOC容器之XmlBeanFactory启动流程分析和源码解析

    一. 前言 Spring容器主要分为两类BeanFactory和ApplicationContext,后者是基于前者的功能扩展,也就是一个基础容器和一个高级容器的区别.本篇就以BeanFactory基 ...

  7. Java多线程- 线程池的基本使用和执行流程分析 - ThreadPoolExecutor

    线程池的实现原理 池化技术 一说到线程池自然就会想到池化技术. 其实所谓池化技术,就是把一些能够复用的东西放到池中,避免重复创建.销毁的开销,从而极大提高性能. 常见池化技术的例如: 线程池 内存池 ...

  8. Android 7.0 WifiMonitor工作流程分析

    2019独角兽企业重金招聘Python工程师标准>>> 在wifi启动扫描的分析过程中,出现了多次WifiMonitor的操作,在此分析一下这个函数是如何工作的. 在Android的 ...

  9. 转:Android之 MTP框架和流程分析

    2019独角兽企业重金招聘Python工程师标准>>> 转载:http://www.cnblogs.com/skywang12345/p/3474206.html 概要 本文的目的是 ...

最新文章

  1. 《C++程序设计POJ》《WEEK7 输入输出和模板》《流操纵算子》《文件读写》《二进制文件读写》...
  2. implementation ‘com.zxy.android:recovery:
  3. Restful API 设计规范实战
  4. Python实训day14am【Python网络爬虫综合大作业-答辩】
  5. android自定义渐变色,Android设置背景渐变色
  6. sql注入修复方法是_旧的方法是修复我们可以看到的内容。
  7. ASP.NET WebApi 基于JWT实现Token签名认证
  8. 铺铜过孔不要十字_谈谈商周青铜器上圈足的镂孔现象
  9. access字体变为斜体_Linux折腾记(四):Linux桌面系统字体配置详解
  10. Linux Shell 重定向到文件以当前时间命名
  11. 论文页眉奇偶页不同怎么设置_还在愁毕业论文的页眉页脚吗?
  12. es内嵌文档查询_ElasticSearch 文档的增删改查都不会?
  13. WinForm C#全局错误捕捉处理【整理】
  14. inchat库下载 python_Linux 环境下安装 Python3 的操作方法
  15. 王者调整期选股技术之喇叭花开
  16. OpenGL ES on iOS --- 光照进阶
  17. 【Cadence 17.2】02 添加封装库/焊盘库
  18. cmos逻辑门传输延迟时间_边沿触发器 || D触发器 || JK触发器 || 逻辑功能转换 工作特性 || 重难点 || 数电...
  19. PLSQL Developer多 表 查 询
  20. 【Spring Cloud 基础设施搭建系列】Spring Cloud Demo项目 整合Spring Data JPA

热门文章

  1. Qt LineEdit 光标文本位置+设置图标问题
  2. 重庆云内核受邀参展第17届中博会
  3. 《像外行一样思考,像专家一样实践》---大智若愚
  4. mysql时序性数据库_时序数据库入门
  5. css 背景效果_前端初学大纲03~(CSS 概述)
  6. CONVMIXER: FEATURE INTERACTIVE CONVOLUTION WITH CURRICULUM LEARNING FOR SMALL FOOTPRINT AND...(2021)
  7. 【蓝桥杯单片机组模块】4、按键模块
  8. 大型项目物资管理方法
  9. js向上向下取整_js向上取整,向下取整,四舍五入,取绝对值等函数
  10. macpro2011年末机器换硬盘免装系统迁移数据