深挖Openstack Nova - 实例创建(2)

本文详细解析了OpenStack Nova组件中实例创建流程的关键步骤——镜像展示(show)方法的实现细节,包括如何通过调用Glance服务获取实例镜像、处理镜像数据以及连接Glance客户端的具体过程。

--------------- 紧接上篇 nova实例创建(1)--------------------


3. 分析show方法

在2.1中的image = self.image_service.show(context, internal_id)中,由于S3是EC2的存储平台,所以调用/nova/image/s3.py的show方法

def show(self, context, image_id):
    # 参数image_id:实例镜像的ID值,是由ec2_id值变换格式后而来
    # id_to_glance_id:根据实例镜像image_id,查询数据库,找到匹配的S3Image的表信息
    # 获取它的S3Image.uuid并返回,赋值给image_uuid
    image_uuid = ec2utils.id_to_glance_id(context, image_id)

    # 这里的service是获取的service或者是GlanceImageService的对象
    #(由glance.get_default_image_service()而来)
    iamge = self.service.show(context, image_uuid)

    # 转换镜像中的image_uuid到image_id
    # 更新image当中的相关属性,返回更新后的image数据
    return self._translate_uuid_to_id(context, image)复制代码

其中,在image = self.service.show(context, image_uuid)中可查到:

self.service = service or glance.get_default_image_service()复制代码

这里的get_default_image_service()对应的是/nova/image/glance.py文件。

可以看到,这里的service获取的类GlanceImageService的实例对象,调用的是该对象里面的show方法:

# 以字典的形式返回给定image_id的镜像image数据
# 调用glance客户端,获取image_id指定的镜像元数据(此时为JSON格式)
# 转换从glance下载的镜像数据为python可处理的字典格式
def show(self, context, image_id, include_location=False,
        show_deleted=True)复制代码


3.1 设置glance客户端的版本

# glance客户端有两个版本
# 初始版本为1
version = 1
# include_locations:可选参数
# 决定image service API是否支持返回的镜像字典信息中包括地址
# 如果支持,选择版本为2的glance客户端
if include_locations:
    version = 2
复制代码


3.2 调用call方法去连接glance客户端,获取image数据

# call:调用一个glance客户端的对象,调用其中的get方法,获取镜像image元数据
# 这个方法尝试一定次数连接glance,从glance客户端下载image
# 如果连接成功,这时会获取glance客户端对象
try:
    image = self._client.call(context, version, 'get', image_id)
except Exception:
    _reraise_translated_image_exception(image_id)
复制代码


3.3 获取image数据后,做正确性验证

# show_deleted:可选参数,当参数为true,表示处于已删除状态的image也显示出来
# 检测image是否被删除
if not show_deleted and getattr(image, 'deleted', False):
    raise exception.ImageNotFound(image_id=image_id)

# 检测image的可用性
if not _is_image_available(context, image):
    raise exception.ImageNotFound(image_id=image_id)
复制代码


3.4 image数据格式转换

# 把通过glance客户端获取的镜像image元数据转换为python可处理的数据格式(原为JSON格式)
image = _translate_form_glance(iamge,
                                include_locations=include_locations)复制代码


3.5 处理返回的image数据中location地址信息,最后返回image

# 通过镜像image拼装location地址
if include_locations:
    locations = image.get('locations', None) or []
    du = image.get('direct_url', None)
    if du:
        locations.append({'url': du, 'metadata': {}})
    iamge['locations'] = locations

return image复制代码


4. 分析call方法

从3.2的image = self._client.call(context, version, 'get', image_id)可知通过call方法去连接glance客户端,从而获取镜像image元数据

# 调用一个glance客户端的对象,调用其中的get方法,获取image镜像
# 尝试一定次数连接glance,如果连接成功,则会获取glance客户端对象,并返回client.images.get
# 如果到达最大尝试连接次数都没有连接成功,则会抛出异常
def call(self, context, version, method, *args, **kwargs):复制代码


4.1 定义异常的类型

# 各种异常
retry_excs = (glanceclient.exc.ServiceUnavailable,
        glanceclient.exc.InvalidEndpoint,
        glanceclient.exc.CommunicatinError)复制代码


4.2 设置重试次数

# 定义当从glance下载image镜像时,重试的次数
# 默认为0,表示会重试无数次
retries = CONF.glance.num_retries
if retries < 0:
    LOG.warning(_LW("Treating negative config value (%(retries)s) for "
                    "glance.num_retries" as 0."),
                {'retries': retries})
    retries = 0
# 加1是为了避免无数次下载尝试的可能性,从而定位为1次重试机会
num_attempts = retries + 1复制代码


4.3 循环尝试获取glance客户端对象

for attempt in range(1, num_attempts + 1):
    # 得到glance客户端对象,如果没有定义,则新建立一个客户端对象
    client = self.client or self._create_onetime_client(context,
                                                        version)
    # 传进来的method是get,所有返回的是getattr
    # 调用的是客户端对象类中的get方法,获取image镜像
    try:
        return getattr(client.images, method)(*args, **kwargs)复制代码

其中,self._create_onetime_client(context, version)表示的是尝试建立并返回一个正确的glanceclient.Client客户端:

# 建立并返回一个正确的glanceclient.Client客户端,它会被用于一次call
def _create_onetime_client(self, context, version):
    # 返回的是不断循环的api_servers列表中的元素(因为执行了:itertools.cycle)
    if self.api_servers is None:
        self.api_servers = get_api_servers()

    # 从api_servers中随机获取某一个元素,进而获取一组host、post、use_ssl的值
    # 用于后续建立glance客户端
    self.host, self.post, self.use_ssl = next(self.api_servers)
    return _create_glance_client(context,
                                 self.host, self.port,
                                 self.use_ssl, version)复制代码

深入_create_glance_client方法,该方法实现了实例化一个正确的新的glanceclient.Client对象

# 实例化一个正确的新的glanceclient.Client对象
# 在python-glanceclient中一共定义了两个版本的客户端:
# glanceclient.v1和glanceclient.v2
def _create_glance_client(context, host, post, use_ssl, version=1):复制代码

(1)决定scheme类型是采用http还是https

params = {}
if use_ssl:
    # https协议是由SSL-HTTP协议构建的
    scheme = 'https'
    # 定义是否执行不安全的SSL协议(https)
    params['insecure'] = CONF.glance.api_insecure
    params['ssl_comopression'] = False
    sslutils.is_enabled(CONF)
    if CONF.ssl.cert_file:
        params['cert_file'] = CONF.ssl.cert_file
    if CONF.ssl.key_file:
        params['key_file'] = CONF.ssl.key_file
    if CONF.ssl.ca_file:
        params['cacert'] = CONF.ssl.ca_file
else:
    scheme = 'http'
复制代码

(2)定义身份认证策略

# 定义身份认证所使用的策略是noauth或者是keystone
if CONF.auth_strategy == 'keystone':
    params['token'] = context.auth_token
    params['identity_headers'] = generate_identity_headers(context)
复制代码

(3)判断host是否需要转换为ipv6格式

# 转换ipv6格式:用[]包围住
if netutils.is_valid_ipv6(host):
    host = '[%s]' % host
复制代码

(4)组装合适的URL形式,并调用glanceclient.Client去获取数据

# endpoint:访问glance api服务的端点
# 组成能够访问glance api service的URL形式
endpoint = '%s://%s:%s' % (scheme, host, post)
# 获取正确的glanceclient.version.client.Client类
return glanceclient.Client(str(version), endpoint, **params)复制代码


4.4 对循环过程中出现的异常做处理

except retry_excs as e:
    host = self.host
    port = self.port

    # 根据重试次数区分不同的错误信息
    if attempt < num_attempts:
        extra = "retrying"
    else:
        extra = 'done trying'

    LOG.exception(_LE("Error contacting glance server "
                      "'%(host)s:%(port)s' for '%(method)s', "
                      "%(extra)s."),
                 {'host': host, 'port': port,
                  'method': method, 'extra': extra})
复制代码


4.5 处理当达到最大连接尝试数的情况

# 如果达到了最大的尝试下载次数,则会抛出异常,提示glance连接失败
if attempt == num_attempts:
    raise exception.GlanceConnectionFailed(
            host=host, port=port, reason=six.text_type(e))
time.sleep(1)复制代码



(未完待续...)

转载于:https://juejin.im/post/5b0e7360518825156010b279

### 安装 OpenStack Nova 组件 可以通过 `yum` 命令来安装 OpenStack Nova 的相关组件,具体命令如下: ```bash yum -y install openstack-nova-api openstack-nova-conductor openstack-nova-scheduler openstack-nova-novncproxy ``` 此命令将会自动下载并安装所需的依赖项以及指定的服务组件[^1]。 --- ### 配置 OpenStack Nova 服务 完成安装后,需要对这些服务进行必要的配置。以下是主要步骤说明: #### 修改主配置文件 编辑 `/etc/nova/nova.conf` 文件以调整调度器的行为。例如,为了实现定期扫描计算节点的功能,可以在 `[scheduler]` 节下添加以下参数: ```ini [scheduler] discover_hosts_in_cells_interval = 300 ``` 这表示每隔 300 秒(即 5 分钟)扫描一次计算节点中的主机状态[^4]。 保存更改后重启 API 服务以使新配置生效: ```bash systemctl restart openstack-nova-api.service ``` --- ### 启动与设置开机自启 安装完成后,需手动启动各个 Nova 相关服务,并将其设为随系统启动而运行: ```bash systemctl start openstack-nova-api openstack-nova-scheduler openstack-nova-conductor openstack-nova-novncproxy systemctl enable openstack-nova-api openstack-nova-scheduler openstack-nova-conductor openstack-nova-novncproxy ``` 以上操作确保了所有核心服务正常运行并能够在下次系统启动时自动加载[^2]。 --- ### 创建管理接口端点 如果尚未创建 Nova 的管理员服务端点,则可通过以下命令完成初始化工作: ```bash openstack endpoint create --region RegionOne nova admin http://<control_node_ip>:8774/v2.1 ``` 其中 `<control_node_ip>` 应替换为实际的控制器节点 IP 地址。成功执行该命令后,将返回包含字段及其对应值的结果表单,确认端点已正确注册到 Keystone 中[^3]。 --- ### 总结 综上所述,通过 Yum 源安装 OpenStack Nova 组件的过程涉及以下几个方面: 1. 使用 `yum` 工具批量安装所需软件包; 2. 编辑配置文件优化功能选项; 3. 手动激活各子服务并将它们加入系统的引导序列; 4. 注册相应的访问入口至身份验证框架内。 按照上述指导即可顺利完成基础环境搭建任务。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值