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向消息中间件中发送消息。
创建时实例数据參数值:
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创建网络。
创建网络步骤例如以下:
參数说明:
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()步骤例如以下:
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是通过请求-响应的方式来完毕的。
请求认证的方式有两种,一种将用户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服务内容组件结构例如以下。
当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': [],
}]