openstack学习笔记一 虚拟机启动过程代码跟踪

时间:2022-12-23 19:56:47

openstack学习笔记一 虚拟机启动过程代码跟踪

本文主要通过对虚拟机创建过程的代码跟踪,观察虚拟机启动任务状态的变化,来透彻理解openstack各组件之间的作用过程。

 当从horizon界面发送一个创建虚拟机请求。horizon api 将会依据前端给定的数据信息。调用novaclient 生成一个创建虚拟机的http post 请求来创建vm服务。

>/usr/lib/python2.6/site-packages/horizon/api/nova.py(334)server_create()

> /usr/lib/python2.6/site-packages/novaclient/base.py(149)_create()

  ->        _resp, body = self.api.client.post(url, body=body)

说明:

此时self.api:<novaclient.v1_1.client.Clientobject >

self.api.client:<novaclient.client.HTTPClientobject>

 

>/usr/lib/python2.6/site-packages/novaclient/client.py(216)_cs_request()

在_rs_request 假设management_url为空。则须要调用keystone的

authenticate()(该方法位于>/usr/lib/python2.6/site-packages/keystone/service.py(252)authenticate()中)方法进行keystone认证。此处创建虚拟机,因为用户已经登陆系统,则management_url不为空,已经经过keystone认证过。故无需再次进行keystone认证。

Eg:发送认证请求的请求參数:

url

u'http://172.30.51.164:8774/v1.1/1c56ca83be0944009499481e90e184dd'

headers

{'X-Auth-Project-Id':u'1c56ca83be0944009499481e90e184dd', 'X-Auth-Key':u'648cc1397bee44eb951399c43155a402', 'X-Auth-User': u'opadmin'}

 

 

>/usr/lib/python2.6/site-packages/novaclient/client.py(209)_time_request()

參数:

Self:<novaclient.client.HTTPClient object>

url:u'http://172.30.51.164:8774/v1.1/1c56ca83be0944009499481e90e184dd/servers'

method:”POST”

kwargs:

{'body':{'server': {'name': u'vm_test', 'imageRef':'e540ef5b-baf0-417e-b6c2-3a0364af25d5', 'availability_zone': u'nova','flavorRef': '6', 'max_count': 1, 'min_count': 1, 'security_groups': [{'name':u'default'}]}}, 'headers': {'X-Auth-Project-Id': u'1c56ca83be0944009499481e90e184dd','X-Auth-Token': u'd9ce4438b914442397f3fdeeb673b30a'}}

 

>/usr/lib/python2.6/site-packages/novaclient/client.py(184)request()

184  ->        resp, body = super(HTTPClient, self).request(*args, **kwargs)

參数:

Args:

self =<novaclient.client.HTTPClient object at 0x7f14d5c1b950>

args =(u'http://172.30.51.164:8774/v1.1/1c56ca83be0944009499481e90e184dd/servers','POST')

kwargs ={'body': '{"server": {"name": "vm_test","imageRef": "e540ef5b-baf0-417e-b6c2-3a0364af25d5","availability_zone": "nova", "flavorRef":"6", "max_count": 1, "min_count": 1,"security_groups": [{"name": "default"}]}}','headers': {'X-Auth-Project-Id': u'1c56ca83be0944009499481e90e184dd','User-Agent': 'python-novaclient', 'Content-Type': 'application/json','Accept': 'application/json', 'X-Auth-Token':u'd9ce4438b914442397f3fdeeb673b30a'}}

 

即调用httplib中

>/usr/lib/python2.6/site-packages/httplib2/__init__.py(1600)request()--httplib

1605                        (response, content) =self._request(conn, authority, uri, request_uri, method, body, headers,redirections, cachekey)

參数说明:

Conn:<httplib2.HTTPConnectionWithTimeout instance>

Authority:u'172.30.51.164:8774'

Uri:u'http://172.30.51.164:8774/v1.1/1c56ca83be0944009499481e90e184dd/servers'

request_uri:u'/v1.1/1c56ca83be0944009499481e90e184dd/servers'

method:'POST'

body:

'{"server":{"name": "vm_test", "imageRef":"e540ef5b-baf0-417e-b6c2-3a0364af25d5","availability_zone": "nova", "flavorRef":"6", "max_count": 1, "min_count": 1,"security_groups": [{"name": "default"}]}}'

 Headers:

{'x-auth-project-id':u'1c56ca83be0944009499481e90e184dd', 'accept-encoding': 'gzip, deflate','accept': 'application/json', 'x-auth-token':u'd9ce4438b914442397f3fdeeb673b30a', 'user-agent': 'python-novaclient','content-type': 'application/json'}

Redirections:5

Cachekey:None

 

请求发出后,openstack中的wsgi 服务将会接收并处理该请求:

 

虚拟机启动过程中任务状态:

任务状态变化:

Status     Task                         Power state        Steps

Build        scheduling                   None               3-12

Build        networking                 None              22-24

Build        block_device_mapping     None                 25-27

Build        spawing                 None               28

Active      none                        Running

 

当请求从前端发送后,wsgicontroller 接受请求后进入nova-api 处理过程:

 

/usr/lib/python2.6/site-packages/nova/api/openstack/compute/servers.py(714)create()

    (instances, resv_id) =self.compute_api.create(context,......

 

>/usr/lib/python2.6/site-packages/nova/compute/api.py(651)create()

 

>/usr/lib/python2.6/site-packages/nova/compute/api.py(233)_create_instance()

 

>/usr/lib/python2.6/site-packages/nova/image/glance.py(235)show() 通过image_href获取get-image信息

 

>/usr/lib/python2.6/site-packages/nova/compute/api.py(406)_create_instance()  写nova.instances数据库,此时vm_status=buildingtask_vm=scheduling

 

>/usr/lib/python2.6/site-packages/nova/compute/api.py(433)_create_instance()

 

>/usr/lib/python2.6/site-packages/nova/compute/api.py(600)_schedule_run_instance()

 

>/usr/lib/python2.6/site-packages/nova/compute/api.py(627)_schedule_run_instance()向消息中间件中发送消息,rpc.cast 方法

 

>/usr/lib/python2.6/site-packages/nova/api/openstack/compute/servers.py(762)create()返回全部创建的虚拟机

 

>/usr/lib/python2.6/site-packages/nova/api/openstack/compute/views/servers.py(64)create()依据消息中间件中返回的虚拟机对象信息构造返回前端显示的虚拟机实例对象

 

_schedule_run_instance方法中。调用rpc向消息中间件中发送消息。

openstack学习笔记一 虚拟机启动过程代码跟踪

 

创建时实例数据參数值:

FLAGS.scheduler_topic:scheduler

FLAGS.compute_topic:computer

Request_spec:

{'num_instances':1, 'block_device_mapping': [], 'image': {'status': 'active', 'name':'cirros-0.3.0-x86_64', 'deleted': False, 'container_format': 'ovf','created_at': '2014-10-28 18:56:51', 'disk_format': 'raw', 'updated_at':'2014-10-28 18:56:51', 'properties': {'description': 'cirros-0.3.0-x86_64'},'min_ram': '512', 'checksum': '50bdc35edb03a38d91b1b071afb20a3c', 'min_disk':'1', 'is_public': True, 'deleted_at': None, 'id':'e540ef5b-baf0-417e-b6c2-3a0364af25d5', 'size': 9761280}, 'instance_type':{'root_gb': 1L, 'name': u'testflav', 'deleted': False, 'created_at':datetime.datetime(2014, 10, 28, 21, 23, 5), 'ephemeral_gb': 0L, 'updated_at':None, 'memory_mb': 512L, 'vcpus': 1L, 'flavorid': u'6', 'swap': 0L,'rxtx_factor': 1.0, 'extra_specs': {u'connections': u'1024', u'bandwidth':u'2'}, 'deleted_at': None, 'vcpu_weight': None, 'id': 6L},'instance_properties': {'vm_state': 'building', 'ephemeral_gb': 0L,'access_ip_v6': None, 'access_ip_v4': None, 'kernel_id': '', 'key_name': None,'ramdisk_id': '', 'instance_type_id': 6L, 'user_data': '', 'vm_mode': None,'display_name': u'test_vm', 'config_drive_id': '', 'reservation_id': 'r-tq6swy2p','key_data': None, 'root_gb': 1L, 'user_id':u'5cd9af0bd8c94f0287eae6919b3a8160', 'uuid':u'52e9f1ad-9983-42ce-ab8a-ed7685d2fcb7', 'root_device_name': None,'availability_zone': u'nova', 'launch_time': '2014-10-29T00:06:20Z','metadata': {}, 'display_description': u'test_vm', 'memory_mb': 512L,'launch_index': 0, 'vcpus': 1L, 'locked': False, 'image_ref':u'e540ef5b-baf0-417e-b6c2-3a0364af25d5', 'architecture': None, 'power_state':0, 'auto_disk_config': None, 'progress': 0, 'os_type': None, 'project_id':u'1c56ca83be0944009499481e90e184dd', 'config_drive': ''}, 'security_group':[u'default']}

admin_password:'H2pGHU9xHpF5'

injected_files:[]

requested_networks:None

filter_properties: {'scheduler_hints': {}}

 

当compute api 发送run_instance消息到消息队列后,compute server将接收消息队列中的消息,并运行指定的方法。

 

>/usr/lib/python2.6/site-packages/nova/compute/manager.py(460)_run_instance()

 

>/usr/lib/python2.6/site-packages/nova/compute/manager.py(576)_start_building() 将正在创建的vm的vm_state改动为building状态。此时,task_state还处于scheduling

 

> /usr/lib/python2.6/site-packages/nova/compute/manager.py(585)_allocate_network()为vm分配网络,vmvm_state改动为building状态,此时。task_state 进入networking状态

 

>/usr/lib/python2.6/site-packages/nova/network/api.py(164)allocate_for_instance()通过网络api 进入network相关组件为vm创建网络。

创建网络步骤例如以下:

openstack学习笔记一 虚拟机启动过程代码跟踪

參数说明:

FLAGS.network_topic :'network'

Args :

self =<nova.network.api.API object at 0x1dd0d90>

context= <nova.rpc.amqp.RpcContext object at 0x32bb850>

instance= <nova.db.sqlalchemy.models.Instance object at 0x374da50>

kwargs ={'instance_uuid': u'37efb12b-aed5-485c-bafc-7ebe9e923c05', 'vpn': False,'requested_networks': None, 'instance_id': 14L, 'host': u'guoyl','rxtx_factor': 1.0, 'project_id': u'1c56ca83be0944009499481e90e184dd'}

消息队列返回结果举例:

nw_info :

[{u'meta':{}, u'network': {u'bridge': u'br100', u'label': u'bss1173', u'meta':{u'tenant_id': None, u'multi_host': True, u'should_create_bridge': True,u'bridge_interface': u'eth0'}, u'id': u'15577a4d-5a16-42a4-88da-17e5773253ca',u'subnets': [{u'ips': [{u'meta': {}, u'type': u'fixed', u'version': 4,u'address': u'10.0.0.2', u'floating_ips': []}], u'version': 4, u'meta':{u'dhcp_server': u'10.0.0.3'}, u'dns': [{u'meta': {}, u'type': u'dns',u'version': 4, u'address': u'8.8.4.4'}], u'routes': [], u'cidr': u'10.0.0.0/24',u'gateway': {u'meta': {}, u'type': u'gateway', u'version': 4, u'address':u'10.0.0.1'}}, {u'ips': [], u'version': None, u'meta': {u'dhcp_server':u'10.0.0.3'}, u'dns': [], u'routes': [], u'cidr': None, u'gateway': {u'meta':{}, u'type': u'gateway', u'version': None, u'address': None}}]}, u'address':u'fa:16:3e:36:1b:52', u'id': u'6faf6db7-d044-41bf-a12e-363efef98474'}]

 

>/usr/lib/python2.6/site-packages/nova/network/api.py(180)allocate_for_instance()

调用network api 去创建网络,并返回获取新创建的网络信息:

输入:[{u'meta': {}, u'network':{u'bridge': u'br100', u'label': u'bss1173', u'meta': {u'tenant_id': None,u'multi_host': True, u'should_create_bridge': True, u'bridge_interface':u'eth0'}, u'id': u'15577a4d-5a16-42a4-88da-17e5773253ca', u'subnets': [{u'ips':[{u'meta': {}, u'type': u'fixed', u'version': 4, u'address': u'10.0.0.2',u'floating_ips': []}], u'version': 4, u'meta': {u'dhcp_server': u'10.0.0.3'},u'dns': [{u'meta': {}, u'type': u'dns', u'version': 4, u'address':u'8.8.4.4'}], u'routes': [], u'cidr': u'10.0.0.0/24', u'gateway': {u'meta': {},u'type': u'gateway', u'version': 4, u'address': u'10.0.0.1'}}, {u'ips': [],u'version': None, u'meta': {u'dhcp_server': u'10.0.0.3'}, u'dns': [],u'routes': [], u'cidr': None, u'gateway': {u'meta': {}, u'type': u'gateway',u'version': None, u'address': None}}]}, u'address': u'fa:16:3e:36:1b:52',u'id': u'6faf6db7-d044-41bf-a12e-363efef98474'}]

输出:

VIF({'network':Network({'bridge': u'br100', 'subnets': [Subnet({'ips': [FixedIP({'meta': {},'version': 4, 'type': u'fixed', 'floating_ips': [], 'address': u'10.0.0.2'})],'version': 4, 'meta': {u'dhcp_server': u'10.0.0.3'}, 'dns': [IP({'meta': {},'version': 4, 'type': u'dns', 'address': u'8.8.4.4'})], 'routes': [], 'cidr':u'10.0.0.0/24', 'gateway': IP({'meta': {}, 'version': 4, 'type': u'gateway','address': u'10.0.0.1'})}), Subnet({'ips': [], 'version': None, 'meta':{u'dhcp_server': u'10.0.0.3'}, 'dns': [], 'routes': [], 'cidr': None,'gateway': IP({'meta': {}, 'version': None, 'type': u'gateway', 'address':None})})], 'meta': {u'tenant_id': None, u'multi_host': True,u'should_create_bridge': True, u'bridge_interface': u'eth0'}, 'id':u'15577a4d-5a16-42a4-88da-17e5773253ca', 'label': u'bss1173'}), 'meta': {},'id': u'6faf6db7-d044-41bf-a12e-363efef98474', 'address': u'fa:16:3e:36:1b:52'})

 

网络创建完毕后,进入准备block_device过程。此时vmvm_state改动为building状态,task_state 进入task_states.BLOCK_DEVICE_MAPPINGblock_device_mapping)状态。

>/usr/lib/python2.6/site-packages/nova/compute/manager.py(610)_prep_block_device()

 

输入:<nova.db.sqlalchemy.models.Instance>

输出:{'block_device_mapping':[], 'root_device_name': None, 'ephemerals': [], 'swap': None}

 

获取完块存储信息后,虚拟机进入spawning过程:此时vmvm_state改动为building状态。task_state 进入task_states.SPAWNINGspawning)状态。

> /usr/lib/python2.6/site-packages/nova/compute/manager.py(622)_spawn()步骤例如以下:

openstack学习笔记一 虚拟机启动过程代码跟踪

 

Spawn过程中,self.driver 对象为<nova.virt.libvirt.connection.LibvirtConnection object>

输入:

Instance:<nova.db.sqlalchemy.models.Instanceobject>

 

image_meta:

{'status':'active', 'name': 'cirros-0.3.0-x86_64', 'deleted': False, 'container_format':'ovf', 'created_at': datetime.datetime(2014, 10, 28, 18, 56, 51),'disk_format': 'raw', 'updated_at': datetime.datetime(2014, 10, 28, 18, 56,51), 'id': 'e540ef5b-baf0-417e-b6c2-3a0364af25d5', 'min_ram': '512','checksum': '50bdc35edb03a38d91b1b071afb20a3c', 'min_disk': '1', 'is_public':True, 'deleted_at': None, 'properties': {'description': 'cirros-0.3.0-x86_64'},'size': 9761280}

 

self._legacy_nw_info(network_info):

[({'bridge':u'br100', 'multi_host': True, 'bridge_interface': u'eth0', 'cidr_v6': None,'vlan': None, 'injected': False, 'cidr': u'10.0.0.0/24', 'id':u'15577a4d-5a16-42a4-88da-17e5773253ca'}, {'rxtx_cap': 0,'should_create_bridge': True, 'dns': [u'8.8.4.4'], 'ip6s': [], 'label':u'bss1173', 'broadcast': '10.0.0.255', 'ips': [{'ip': u'10.0.0.2', 'netmask':'255.255.255.0', 'enabled': '1', 'gateway': u'10.0.0.1'}], 'mac':u'fa:16:3e:36:1b:52', 'vif_uuid': u'6faf6db7-d044-41bf-a12e-363efef98474','should_create_vlan': False, 'gateway_v6': None, 'dhcp_server': u'10.0.0.3','gateway': u'10.0.0.1'})]

 

block_device_info:

{'block_device_mapping':[], 'root_device_name': None, 'ephemerals': [], 'swap': None}

Inject_files:[]

admin_pass:MeWoHq7i2Z8'

输出:instance

 

当虚拟机spawn完毕后,vmvm_state改动为active状态,task_state 置空。为None状态且vm的电源状态为Running状态。

此时,虚拟机创建过程完毕。

调用spawn方法实际上就是调用

>/usr/lib/python2.6/site-packages/nova/virt/libvirt/connection.py(964)spawn()

运行步骤例如以下:

将信息写入到libvirt xml模板

依据network-info创建对应的网络

创建虚拟机启动所须要的镜像文件

调用libvirt 接口define一个虚拟机domain

调用libvirt接口 create vmdomain

轮询vm状态。当vm 为running状态时返回

 

 

Openstack  keystone 认证过程

 

Openstack中的keystone是通过请求-响应的方式来完毕的。

请求认证的方式有两种,一种将用户password等信息放在request headers中(_v1_auth)。如token认证;另外一种将认证信息放在请求body 中(_v2_auth)。请求时都需带auth_url 參数。

第一种方式:

request(url,'GET', headers=headers)

headers = {'X-Auth-User': self.user,

              'X-Auth-Key': self.password,

'X-Auth-Project-Id': self.projectid}

另外一种方式:

request(token_url,"POST", body=body)。当中token_url = url + "/tokens"

body = {"auth": {

                "passwordCredentials": {

"username": self.user,

                            "password": self.password}

}

"tenantName": projectid

}

 

当keystone服务内容组件结构例如以下。

openstack学习笔记一 虚拟机启动过程代码跟踪

当service接受认证请求后,或调用authenticate()方法来处理请求。经过一系列的认证处理后,返回_format_authenticate(token_ref, roles_ref, catalog_ref)。返回json数据格式例如以下:

{'access': {'token': {'id': token_ref['id'],

                                  'expires': expires,

                                  'tenant' : {‘enable’:true,……}

                                  },

               'user': {'id': user_ref['id'],

                          'name': user_ref['name'],

                          'username': user_ref['name'],

                          'roles': roles_ref,

                         'roles_links':metadata_ref.get('roles_links',[])

                          },

               serviceCatalog : catalog_ref

              }

 }

Catalog_ref:

        [{'name': $SERVICE[name],

          'type': $SERVICE,

          'endpoints': [{

              'tenantId': $tenant_id,

              ...

              'region': $REGION,

              }],

          'endpoints_links': [],

         }]