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出现乱码怎么解决 openstack代码_keystone

 

创建时实例数据参数值:

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分配网络,vm的vm_state修改为building状态,此时,task_state 进入networking状态

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

openstack出现乱码怎么解决 openstack代码_虚拟机启动状态_02

参数说明:

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过程;此时,vm的vm_state修改为building状态,task_state 进入task_states.BLOCK_DEVICE_MAPPING(block_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过程:此时,vm的vm_state修改为building状态,task_state 进入task_states.SPAWNING(spawning)状态。

> /usr/lib/python2.6/site-packages/nova/compute/manager.py(622)_spawn()过程如下:

openstack出现乱码怎么解决 openstack代码_虚拟机启动状态_03

 

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完成后,vm的vm_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是通过请求-响应的方式来完成的。

请求认证的方式有两种,一种将用户密码等信息放在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':.projectid}
第二种方式:
request(token_url,"POST", body=body);其中token_url = url + "/tokens"
body = {"auth": {
                "passwordCredentials": {
"username":  self.user,
                            "password": self.password}
}
"tenantName": projectid
}

当keystone服务内容组件结构如下,

openstack出现乱码怎么解决 openstack代码_虚拟机启动_04

当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': [],
         }]