分享

openstack接管vCenter

ruyang 发表于 2015-5-7 16:55:25 [显示全部楼层] 回帖奖励 阅读模式 关闭右栏 1 28199
1. openstack接管vCenter中已有的VM,通过VNC链接VM

代码添加以及调研流程

1): horizon代码
在api/nova.py中添加以下方法,该方法调研novaclient中get_vnc_console_for_vmware方法
def get_vnc_console_for_vmware(request, hypervisor,
                          instance_id,
                          host, console_type='novnc'):       
    return VNCConsole(novaclient(request).
                      vms_hypervisors.
                      get_vnc_console_for_vmware(hypervisor,
                          instance_id, host,
                                                  console_type=console_type)['console'])

2): novaclient代码
在novaclient/v1.1/servers.py中添加get_vnc_console_for_vmware方法,如下:


def get_vnc_console_for_vmware(self, server, console_type,
                                   host, service_host):
        """
        Get a vnc console for an instance


        :param server: The :class:`Server` (or its ID) to add an IP to.
        :param console_type: Type of vnc console to get ('novnc' or 'xvpvnc')
        """


        return self._action('os-getVNCConsoleVmware', server,
                            {'type': console_type,
                             'host': host,
                             'service_host': service_host})[1]

该方法通过wsgi设置的os-getVNCConsoleVmware调用nova api中的get_vnc_console_for_vmware方法


3): nova代码
在nova/api/openstack/compute/contrib/consoles.py中添加如下方法:
@wsgi.action('os-getVNCConsoleVmware')
    def get_vnc_console_for_vmware(self, req, id, body):
        """Get vnc connection information to access a server."""
        context = req.environ['nova.context']
        authorize(context)


        # If type is not supplied or unknown, get_vnc_console below will cope
        console_type = body['os-getVNCConsoleVmware'].get('type')
        host = body['os-getVNCConsoleVmware'].get('host')
        hypervisor_name = body['os-getVNCConsoleVmware'].get('hypervisor_name')
        compute_nodes = self.host_api.compute_node_search_by_hypervisor(context, hypervisor_name)
        service_host = compute_nodes[0].service.host
        try:
            output = self.compute_api.get_vnc_console_for_vmware(context,
                                                      console_type=console_type,
                                                      instance_id=id,
                                                      host= host,
                                                      service_host=service_host)
        except exception.InstanceNotFound as e:
            raise webob.exc.HTTPNotFound(explanation=e.format_message())
        except exception.InstanceNotReady as e:
            raise webob.exc.HTTPConflict(
                    explanation=_('Instance not yet ready'))
        except NotImplementedError:
            msg = _("Unable to get vnc console, functionality not implemented")
            raise webob.exc.HTTPNotImplemented(explanation=msg)


        return {'console': {'type': console_type, 'url': output['url']}}


该方法中self.compute_api.get_vnc_console_for_vmware调研compute api中的get_vnc_console_for_vmware方法


在nova/compute/api.py中添加get_vnc_console_for_vmware方法如下:
def get_vnc_console_for_vmware(self, context, **kwargs):
        """Get a url to an instance Console."""
        connect_info = self.compute_rpcapi.get_vnc_console_for_vmware(context,
                console_type=kwargs['console_type'], instance_id=kwargs['instance_id'],
                service_host=kwargs['service_host'])


        self.consoleauth_rpcapi.authorize_console_for_vmware(context,
                connect_info['token'], kwargs['console_type'],
                kwargs['host'], connect_info['port'],
                connect_info['internal_access_path'],
                kwargs['instance_id'],kwargs['service_host'])


        return {'url': connect_info['access_url']}


该方法中self.compute_rpcapi.get_vnc_console_for_vmware调用compute repapi中的get_vnc_console_for_vmware方法和
self.consoleauth_rpcapi.authorize_console_for_vmware调用consoleauth repapi中的authorize_console_for_vmware方法


分支一
在nova/compute/rpcapi.py中添加get_vnc_console_for_vmware方法如下代码:
def get_vnc_console_for_vmware(self, ctxt, console_type, **kwargs):
        if self.client.can_send_version('3.2'):
            version = '3.2'
        else:
            # NOTE(russellb) Havana compat
            version = self._get_compat_version('3.0', '2.0')
            #instance = jsonutils.to_primitive(instance)
        cctxt = self.client.prepare(server=kwargs['service_host'],
                version=version)
        return cctxt.call(ctxt, 'get_vnc_console_for_vmware',
                          instance_id=kwargs['instance_id'], console_type=console_type)


该方法通过rpc请求调用nova/compute/manager.py中的get_vnc_console_for_vmware方法


在nova/compute/manager.py中添加get_vnc_console_for_vmware方法代码如下:
def get_vnc_console_for_vmware(self, context, console_type, instance_id):
        """Return connection information for a vnc console."""
        context = context.elevated()
        LOG.debug(_("Getting vnc console instance_id ======== %s ") %  instance_id)
        token = str(uuid.uuid4())


        if not CONF.vnc_enabled:
            raise exception.ConsoleTypeInvalid(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.novncproxy_base_url, token)
        elif console_type == 'xvpvnc':
            access_url = '%s?token=%s' % (CONF.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 token
            connect_info = self.driver.get_vnc_console_for_vmware(context, instance_id)
            connect_info['token'] = token
            connect_info['access_url'] = access_url
        except exception.InstanceNotFound:
            raise exception.InstanceNotReady(instance_id=instance_id)


        return connect_info


该方法中self.driver.get_vnc_console_for_vmware调研nova/virt/vmwareapi/driver.py中的get_vnc_console_for_vmware方法。该方法返回一个字典,
字典中包含token, novnc代理url, vm的vnc端口

在nova/virt/vmwareapi/driver.py中添加get_vnc_console_for_vmware方法如下:
def get_vnc_console_for_vmware(self, context, instance_id):
        """Return link to instance's VNC console."""
        return self._vmops.get_vnc_console_for_vmware(instance_id)

该方法调用nova/vrit/vmwareapi/vmops.py中的get_vnc_console_for_vmware方法:


在nova/vrit/vmwareapi/vmops.py添加get_vnc_console_for_vmware方法如下:
def get_vnc_console_for_vmware(self, instance_id):
        """Return connection info for a vnc console."""
        vm_ref = vm_util._get_vm_ref_from_vm_uuid(self._session, instance_id)
        opt_value = self._session._call_method(vim_util,
                               'get_dynamic_property',
                               vm_ref, 'VirtualMachine',
                               vm_util.VNC_CONFIG_KEY)
        if opt_value:
            port = int(opt_value.value)
        else:
            raise exception.ConsoleTypeUnavailable(console_type='vnc')


        return {'port': port,
                'internal_access_path': None}

该方法返回一个字典,该字典中包含虚拟机(VM)的vnc端口



分支二
在nova/consoleauth/rpcapi.py中添加get_vnc_console_for_vmware方法如下代码:
def authorize_console_for_vmware(self, ctxt, token, console_type, host, port,
                          internal_access_path, instance_uuid, service_host):
        # The remote side doesn't return anything, but we want to block
        # until it completes.'
        version = '2.0'
        if not self.client.can_send_version('2.0'):
            # NOTE(russellb) Havana compat
            version = '1.2'
        cctxt = self.client.prepare(version=version)
        return cctxt.call(ctxt,
                          'authorize_console_for_vmware',
                          token=token, console_type=console_type,
                          host=host, port=port,
                          internal_access_path=internal_access_path,
                          instance_uuid=instance_uuid,
                          service_host=service_host)

该方法通过rpc请求调用nova/consoleauth/manager.py中的authorize_console_for_vmware方法


在nova/consoleauth/manager.py中添加authorize_console_for_vmware方法代码如下:

def authorize_console_for_vmware(self, context, token, console_type, host, port,
                          internal_access_path, instance_uuid, service_host):


        token_dict = {'token': token,
                      'instance_uuid': instance_uuid,
                      'console_type': console_type,
                      'host': host,
                      'port': port,
                      'service_host': service_host,
                      'internal_access_path': internal_access_path,
                      'last_activity_at': time.time()}
        data = jsonutils.dumps(token_dict)
        self.mc.set(token.encode('UTF-8'), data, CONF.console_token_ttl)
        tokens = self._get_tokens_for_instance(instance_uuid)
        # Remove the expired tokens from cache.
        for tok in tokens:
            token_str = self.mc.get(tok.encode('UTF-8'))
            if not token_str:
                tokens.remove(tok)
        tokens.append(token)
        self.mc.set(instance_uuid.encode('UTF-8'),
                    jsonutils.dumps(tokens))


        LOG.audit(_("Received Token: %(token)s, %(token_dict)s"),
                  {'token': token, 'token_dict': token_dict})

该方法注意是用存储token,console_type,instance_uuid等信息,用于验证。

以上代码返回的novnc_proxy_base_url,在浏览器中执行该url时,控制节点的noVNC服务监听到6080 HTTP 端口,接受此URL请求,然后向Nova-consoleauth发送check_token消息。

nova/consoleauth/rpcapi.py中代码:
def check_token(self, ctxt, token):
        version = '2.0'
        if not self.client.can_send_version('2.0'):
            # NOTE(russellb) Havana compat
            version = '1.0'
        cctxt = self.client.prepare(version=version)
        return cctxt.call(ctxt, 'check_token', token=token)


通过rpc调用nova/consoleauth/manager.py中的check_token方法



在nova/consoleauth/manager.py中代码如下:
def check_token(self, context, token):
        token_str = self.mc.get(token.encode('UTF-8'))
        token_valid = (token_str is not None)
        LOG.audit(_("Checking Token: %(token)s, %(token_valid)s"),
                  {'token': token, 'token_valid': token_valid})
        if token_valid:
            token = jsonutils.loads(token_str)
            if 'service_host' in token:
                if self._validate_token_for_vmware(context, token):
                    return token
            else:
                if self._validate_token(context, token):
                    return token



调用_validate_token_for_vmware方法_validate_token_for_vmware方法代码如下:
def _validate_token_for_vmware(self, context, token):
        instance_uuid = token['instance_uuid']
        if instance_uuid is None:
            return False


        # NOTE(comstud): consoleauth was meant to run in API cells.  So,
        # if cells is enabled, we must call down to the child cell for
        # the instance.
        if CONF.cells.enable:
            return self.cells_rpcapi.validate_console_port(context,
                    instance_uuid, token['port'], token['console_type'])


        return self.compute_rpcapi.validate_console_port_for_vmware(context,
                                            instance_id=instance_uuid,
                                            port=token['port'],
                                            console_type=token['console_type'],
                                            service_host=token['service_host'])



该方法调研nova/compute/rpcapi.py中validate_console_port_for_vmware方法:




在nova/compute/rpcapi.py中添加代码如下:
def validate_console_port_for_vmware(self, ctxt, **kwargs):
        if self.client.can_send_version('3.3'):
            version = '3.3'
        else:
            # NOTE(russellb) Havana compat
            version = self._get_compat_version('3.0', '2.26')
        cctxt = self.client.prepare(server=kwargs['service_host'],
                version=version)
        return cctxt.call(ctxt, 'validate_console_port_for_vmware',
                          instance_id=kwargs['instance_id'], port=kwargs['port'],
                          console_type=kwargs['console_type'])



该方法通过rpc调研nova/compute/manager.py中的validate_console_port_for_vmware方法:


在nova/compute/manager.py中添加如下代码:


def validate_console_port_for_vmware(self, ctxt, instance_id, port, console_type):
        console_info = self.driver.get_vnc_console_for_vmware(ctxt, instance_id)


        return console_info['port'] == port

该方法调研driver中的get_vnc_console_for_vmware返回该VM的vnc端口号,然后和传递过来的端口进行比较判断,返回比较结果

已有(1)人评论

跳转到指定楼层
迷糊云 发表于 2016-2-2 07:39:09
mark一下,以后慢慢看
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

推荐上一条 /2 下一条