nova 创建虚拟机流程
来源:互联网 发布:梅雨知时节 作家 编辑:程序博客网 时间:2024/05/21 12:45
1 Nova创建虚机流程
Openstack创建虚拟机的整个流程如图1所示。前端horizon发送创建虚机的请求之后,novaapi接收请求,并作处理,详见1.1节。注:Nova scheduler在另外章节介绍。
图 1 nova创建虚拟机流程
1.1 Nova api
Nova api接受到前端(horizon)发来的创建虚机的请求后,调用create(self, req, body)函数(/opt/stack/nova/nova/api/openstack/compute/servers.pyà1088)。该函数主要获取前端发来的body数据并解析,将相应参数传递给compute api(1.2节)。
1.2 Compute api
Compute api接受到请求之后,调用create函数。
def create(self, context, instance_type,image_href, kernel_id=None, ramdisk_id=None, min_count=None, max_count=None, display_name=None,
display_description=None, key_name=None, key_data=None, security_group=None,availability_zone=None, user_data=None,metadata=None,
injected_files=None, admin_password=None, block_device_mapping=None, access_ip_v4=None,access_ip_v6=None, requested_networks=None, config_drive=None,auto_disk_config=None, scheduler_hints=None, iolimit=None, hypervisor=None):
“””
代码位置:/opt/stack/nova/nova/compute/api.pyà749
部分参数如下:
display_name=test
admin_password=123456
image_href=66c50770-21a4-46ce-85ee-392f29b05081
metadata={}
injected_files=[]
requested_networks={}
min_count=1
max_count=1
instance_type ={'memory_mb': 512L, 'root_gb': 0L, 'deleted_at': None, 'name':u'm1.tiny' , 'deleted': False,'created_at': None, 'ephemeral_gb': 0L, 'updated_at': None, 'disabled': False,'vcpus': 1L, 'extra_specs': {}, 'swap': 0L, 'rxtx_factor': 1.0, 'is_public':True, 'flavorid': u'1', 'vcpu_weight': None, 'id': 4L}
”””
- 检查各种参数及配额
_check_num_instances_quota(context, instance_type, min_count, max_count,hypervisor=hypervisor)
_check_metadata_properties_quota(context, metadata)
_check_injected_file_quota(context, injected_files)
_check_requested_networks(context, requested_networks)
- 获取镜像信息,检查flavor的ram,disk是否超出镜像规定的最小限额
(image_service, image_id) = lance.get_remote_image_service(image_href)
image = image_service.show(context, image_id)
if instance_type['memory_mb'] < int(image.get('min_ram') or 0):
raise exception
if instance_type['root_gb'] < int(image.get('min_disk') or 0):
raise exception - 将参数放入字典base_options={
'vm_state': 'building',
'ephemeral_gb': 0L,
'access_ip_v6': None,
'access_ip_v4': None,
'kernel_id': 'adaf51fe-c235-40b6-8aa7-80216d42303c',
'key_name': None,
'ramdisk_id': 'f9216b02-8e27-44da-b159-8d64401a16f2',
'instance_type_id': 4L,
'user_data':u'IyEvYmluL2Jhc2gKdXNlcmFkZCAtbSByb290CnBhc3N3ZCByb290IDw8IEVPRgpyb290CnJvb3QKRU9GCnBhc3N3ZCByb290IDw8IEVPRgpyb290CnJvb3QKRU9GCg==',
'vm_mode': '',
'display_name': u'test',
'config_drive_id': '',
'reservation_id': 'r-yl00q2af','architecture': 'Unknown',
'key_data': None, 'root_gb': 0L,
'user_id': u'c94cf849c7a94174b18f516c8fe497ee', 'hypervisor':u'libvirt',
'availability_zone': None,
'launch_time': '2014-10-30T05:28:15Z',
'metadata': {},
'display_description': u'test',
'memory_mb': 512L,
'vcpus': 1L,
'locked': False,
'image_ref': u'66c50770-21a4-46ce-85ee-392f29b05081',
'root_device_name': None,
'power_state': 0,
'progress': 0,
'cdrom_active': False,
'project_id': u'1ec9c7671c824b798fb9a028623aaccc',
'config_drive': ''}
- 利用base_options在数据库创建instance
instance = self.create_db_entry_for_new_instance(context, instance_type,image, base_options, security_group, block_device_mapping) - rpc调用启动虚机(发请求到compute manger)
self.scheduler_rpcapi.run_instance(context,request_spec=request_spec, admin_password=admin_password,injected_files=injected_files, requested_networks=requested_networks,is_first_time=True, filter_properties=filter_properties)
1.3 Compute manager
Computemanager收到run_instance的请求后,运行函数run_instance。该函数内部会调用_run_instance函数如下:
def _run_instance(self,context, request_spec, filter_properties, requested_networks, injected_files,admin_password, is_first_time, instance):
“””
代码位置:/opt/stack/nova/nova/compute/manager.pyà510
参数实际值:
request_spec:={
'block_device_mapping':[],
'security_group': [u'default'],
'instance_uuids': ['8383fb3d-7dcf-4203-b639- 14c617b55259']'instance_uuids': ['8383fb3d-7dcf-4203-b639- 14c617b55259']
'instance_uuids': ['8383fb3d-7dcf-4203-b639- 14c617b55259']
'image': {'status': 'active',
'name':'cirros-test-image',
'deleted':False,
'container_format':'ami',
'created_at':'2014-10-30T04:21:05.000000',
'disk_format': 'ami',
'updated_at':'2014-10-30T04:21:09.000000',
'properties': {'kernel_id':'adaf51fe-c235-40b6-8aa7-80216d42303c',
'source': 'nova',
'ramdisk_id':'f9216b02-8e27-44da-b159-8d64401a16f2'},
'min_disk': 0,
'min_ram': 0,
'checksum':'2f81976cae15c16ef0010c51e3a6c163',
'owner':'1ec9c7671c824b798fb9a028623aaccc',
'is_public': True,
'deleted_at': None,
'id':'66c50770-21a4-46ce-85ee-392f29b05081', 'size': 25165824},
'instance_type': {'memory_mb': 512L,
'root_gb': 0L,
'deleted_at': None,
'name': u'm1.tiny',
'deleted': False,
'created_at': None,
'ephemeral_gb': 0L,
'updated_at': None,
'disabled': False,
'vcpus': 1L,
'extra_specs': {},
'swap': 0L,
'rxtx_factor': 1.0,
'is_public': True,
'flavorid': u'1',
'vcpu_weight': None,
'id': 4L},
'instance_properties': {'vm_state': 'building',
'ephemeral_gb': 0L,
'access_ip_v6': None,
'access_ip_v4': None,
'kernel_id': 'adaf51fe-c235-40b6-8aa7-80216d42303c',
'key_name': None,
'ramdisk_id':'f9216b02-8e27-44da-b159-8d64401a16f2', 'instance_type_id': 4L,
'user_data':u'IyEvYmluL2Jhc2gKdXNlcmFkZCAtbSByb290CnBhc3N3ZCByb290IDw8IEVPRgpyb290CnJvb3QKRU9GCnBhc3N3ZCByb290IDw8IEVPRgpyb290CnJvb3QKRU9GCg==',
'vm_mode': None,
'display_name':u'test',
'config_drive_id':'',
'reservation_id':'r-yl00q2af',
'os_type': None,
'architecture': None,
'key_data': None,
'iolimit': None,
'root_gb': 0L,
'user_id':u'c94cf849c7a94174b18f516c8fe497ee',
'hypervisor':u'libvirt',
'availability_zone':None,
'launch_time':'2014-10-30T05:28:15Z',
'metadata': {},
'display_description':u'test',
'memory_mb': 512L,
'vcpus': 1L,
'locked': False,
'image_ref':u'66c50770-21a4-46ce-85ee-392f29b05081', 'root_device_name': None,
'power_state': 0,
'auto_disk_config':None,
'progress': 0,
'cdrom_active':False,
'project_id': u'1ec9c7671c824b798fb9a028623aaccc',
'config_drive': ''}
}
admin_password=123456
injected_files=[]
requested_networks={}
”””
- 查看虚机是否存在
self._check_instance_not_already_created(context, instance)
- 查看镜像大小超过flavor规定最大值
self._check_image_size(context, instance)
- 更新虚机的状态(db)
self._start_building(context, instance)
- 分配网络,见1.4节 network
self._allocate_network
network_info=self.network_api.allocate_for_instance(context,instance,vpn=is_vpn, requested_networks=requested_networks)
- 孵化虚拟机,见1.5节libvirt driver
self.driver.spawn(context, instance, image_meta, network_info, block_device_info, injected_files,admin_password)
1.4 network
1.4.1 network api
networkapi收到compute manager发送的请求之后调用allocate_for_instance,增加一些参数,远程rpc调用将请求发送给network manager。
def allocate_for_instance(self,context, instance, **kwargs):
"""代码位置:/opt/stack/nova/nova/network/api.pyà277
Allocates all network structures for an instance.
:returns: network info as fromget_instance_nw_info() below
"""
args = kwargs
args['instance_id'] = instance['id']
args['instance_uuid'] = instance['uuid']
args['project_id'] = instance['project_id']
args['host'] = instance['host']
args['rxtx_factor'] = instance['instance_type']['rxtx_factor']
nw_info = rpc.call(context, FLAGS.network_topic,
{'method':'allocate_for_instance',
'args': args})
return network_model.NetworkInfo.hydrate(nw_info)
1.4.2 network manager
networkmanager收到请求后,调用函数allocate_for_instance。
def allocate_for_instance(self, context, **kwargs):
"""
代码位置:/opt/stack/nova/nova/network/manager.pyàclass NetworkManagerà1063
"""
- 从数据库获取所有网络networks
注:该网络是在安装时,写入数据库的
networks = self._get_networks_for_instance(admin_context, instance_id,project_id, requested_networks=requested_networks)à 1078
本环境只有一个network
{'bridge': u'br100',
'vpn_public_port': None,
'dhcp_start': u'10.1.0.2',
'bridge_interface': u'eth0',
'updated_at': None,
'id': 1L,
'cidr_v6': None,
'deleted_at': None,
'gateway':u'10.1.0.1',
'rxtx_base': None,
'uuid':u'e011b388-163b-4080-a083-bb63ebed7f6a',
'label':u'private',
'priority': None,
'project_id': None,
'netmask_v6': None,
'_sa_instance_state': <sqlalchemy.orm.state.InstanceStateobject at 0x42c4790>,
'deleted': False,
'vlan': None,
'broadcast':u'10.1.255.255',
'netmask':u'255.255.0.0',
'injected': False,
'cidr':u'10.1.0.0/16',
'vpn_public_address': None,
'multi_host': True,
'dns2': None,
'dns1':u'8.8.4.4',
'host': None,
'gateway_v6': None,
'vpn_private_address': None,
'created_at':datetime.datetime(2014, 10, 30, 4, 22, 44)}
- 分配mac地址
self._allocate_mac_addresses(context, instance_uuid, networks)->1083
mac为自动生成(address=utils.generate_mac_address),返回结果为vif
{'uuid':'7344166b-e3ef-44be-80e3-ecfa5696cce8',
'instance_uuid':u'90844617-d71f-474f-9cdf-35e244c846b0',
'network_id':1L,
'address':'fa:16:3e:76:b4:2f‘}
- 分配fixed ip
self._allocate_fixed_ips(admin_context, instance_id, host, networks,vpn=vpn, requested_networks=requested_networks)->1084
allocate_fixed_ip(self, context, instance_id, network, **kwargs)à2124
1) 从数据库(fixedip池)获取address,本例为10.1.0.2
self.db.fixed_ip_associate_pool(context.elevated(),network['id'],instance_ref['uuid'])->2142)
2) 从数据库获取网卡vif 信息
self.db.virtual_interface_get_by_instance_and_network(context,instance_ref['uuid'],network['id'])->2148)
3) 更新数据库,标示该fixed_ip被分配,对应网卡为vif
注:mac:ip写配置文件/opt/stack/data/nova/networks/nova-br100.conf
values = {'allocated': True,'virtual_interface_id': vif['id']}
self.db.fixed_ip_update(context,address, values)->2152
4) 宿主机建立网络self._setup_network_on_host(context, network)à2153
def_setup_network_on_host(self, context, network):à2055
"""
功能:1.设置dhcp_server的ip
2.创建网桥,并绑定特定网卡
3.设置iptables规则,并应用
"""
#network['dhcp_server']= self._get_dhcp_ip(context, network)从数据库获取,若不存在则从fixedip池中获取。本例为10.1.0.3。
try:
fip = self.db.fixed_ip_get_by_network_host(context,network_id, host)
return fip['address']
except exception.FixedIpNotFoundForNetworkHost:
elevated = context.elevated()
return self.db.fixed_ip_associate_pool(elevated,network_id, host=host)
#self.l3driver.initialize_gateway(network)
/opt/stack/nova/nova/network/l3.py(101)initialize_gateway()
def initialize_gateway(self,network_ref):
mac_address = utils.generate_mac_address()#生成mac地址
#network_ref['gateway']=10.1.0.1àgateway=True
dev = linux_net.plug(network_ref, mac_address,
gateway=(network_ref['gateway'] is not None))
linux_net.initialize_gateway_device(dev, network_ref)
/opt/stack/nova/nova/network/linux_net.py->1106
def plug(self, network, mac_address, gateway=True):
iface = FLAGS.flat_interface ornetwork['bridge_interface'] #iface=eth0
LinuxBridgeInterfaceDriver.ensure_bridge(network['bridge'],
iface, network, gateway)
iptables_manager.apply()
/opt/stack/nova/nova/network/linux_net.py->1168
def ensure_bridge(_self, bridge, interface, net_attrs=None,gateway=True):
# bridge=br100; interface=eth0, gateway=True
if not _device_exists(bridge):#br100若不存在,则创建
_execute('brctl', 'addbr', bridge, run_as_root=True)
_execute('brctl', 'setfd', bridge, 0, run_as_root=True)
_execute('brctl', 'stp', bridge, 'off', run_as_root=True)
_execute('ip', 'link', 'set', bridge, 'up', run_as_root=True)
if interface:
out, err = _execute('brctl', 'addif', bridge, interface, )#绑定网卡
old_routes = []
#显示eth0的route,并删除
out, err = _execute('ip', 'route', 'show', 'dev', interface)
for line in out.split('\n'):
fields = line.split()
if fields and 'via' in fields:
old_routes.append(fields)
_execute('ip', 'route', 'del', *fields, run_as_root=True)
#将eth0的ip删除,并复制给br100
out, err = _execute('ip', 'addr', 'show', 'dev', interface,)
for line in out.split('\n'):
fields = line.split()
if fields and fields[0] == 'inet':
params = fields[1:-1]
_execute(*_ip_bridge_cmd('del', params, fields[-1]),
_execute(*_ip_bridge_cmd('add', params, bridge),
for fields in old_routes:
_execute('ip', 'route', 'add', *fields, run_as_root=True)
#添加规则
ipv4_filter =iptables_manager.ipv4['filter']
if gateway:
ipv4_filter.add_rule('FORWARD',
'--in-interface %s -j ACCEPT' % bridge)
ipv4_filter.add_rule('FORWARD',
'--out-interface %s -j ACCEPT' % bridge)
#self.driver.update_dhcp(context, dev, network)重启dhcpserver
/usr/sbin/dnsmasq--strict-order --bind-interfaces
--conf-file=/opt/stack/data/dnsmasq.conf--domain=novalocal
--pid-file=/opt/stack/data/nova/networks/nova-br100.pid--listen-address=10.1.0.3 --except-interface=lo --dhcp-range=set:'private',10.1.0.2,static,120s--dhcp-lease-max=65536 --dhcp-hostsfile=/opt/stack/data/nova/networks/nova-br100.conf
--dhcp-script=/opt/stack/nova/bin/nova-dhcpbridge --leasefile-ro
- 获取分配给instance的networkinfo
self.get_instance_nw_info(context, instance_id, instance_uuid,rxtx_factor, host)
获得的network_info如下:
[VIF(
{'network':
Network(
{'bridge': u'br100',
'subnets': [
Subnet({‘ips’:[FixedIP({‘meta’: {},
‘version’: 4,
‘type’: u‘fixed’,
‘floating_ips': [],
'address':u'10.1.0.2'})],
'version': 4,
'meta': {u'dhcp_server':u'10.1.0.3'},
'dns': [IP({'meta': {},'version': 4,
'type': u'dns','address': u'8.8.4.4'})],
'routes': [],
'cidr': u'10.1.0.0/16',
gateway': IP({'meta': {}, 'version': 4,
'type': u'gateway',
'address': u'10.1.0.1'})}),
Subnet({'ips': [],
'version': None,
'meta': {u'dhcp_server': u'10.1.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'e011b388-163b-4080-a083-bb63ebed7f6a',
'label': u'private'}),
'meta': {},
'id':u'99a3c937-1a0f-48f7-8015-166d7644e9a0',
'address': u'fa:16:3e:5a:f4:23'})]
1.4.3 nova network 总结
1. 宿主机配置br100(eth0)ip地址为192.168.96.80,
auto br100
iface br100 inet static
address 192.168.96.80
netmask 255.255.255.0
gateway 192.168.96.254
dns-nameservers114.114.114.114
bridge-ports eth0
2. 配置文件
FIXED_RANGE=10.1.0.0/16
FIXED_NETWORK_SIZE=65535
3. nova network 安装时,会执行以下命令,创建networks写入数据库。本例中,只有一个网络。
if [ !"$FIXED_RANGE" = "" ]; then
nova-manage network create private$FIXED_RANGE 1 $FIXED_NETWORK_SIZE
{ 'bridge': u'br100',
'vpn_public_port': None,
'dhcp_start': u'10.1.0.2',
'bridge_interface': u'eth0',
'updated_at': None,
'id': 1L,
'cidr_v6': None,
'deleted_at': None,
'gateway':u'10.1.0.1',
'rxtx_base': None,
'uuid':u'e011b388-163b-4080-a083-bb63ebed7f6a',
'label':u'private',
'priority': None,
'project_id': None,
'netmask_v6': None,
'_sa_instance_state': <sqlalchemy.orm.state.InstanceStateobject at 0x42c4790>,
'deleted': False,
'vlan': None,
'broadcast':u'10.1.255.255',
'netmask':u'255.255.0.0',
'injected': False,
'cidr':u'10.1.0.0/16',
'vpn_public_address': None,
'multi_host': True,
'dns2': None,
'dns1':u'8.8.4.4',
'host': None,
'gateway_v6': None,
'vpn_private_address': None,
'created_at': datetime.datetime(2014, 10, 30,4, 22, 44)}
4. 在创建第一个虚机时,会给宿主机br100分配一个在FIXED_RANGE之内的ip(10.1.0.3),该ip作为该宿主机上vm的dhcpserver来分配ip地址。同时也作为vm的default gateway,与外界通信。
5. 给虚机分配网络时,自动生成mac地址,从数据库选择一个没有用过的fixedip(10.1.0.2),将mac:ip写入配置文件/opt/stack/data/nova/networks/nova-br100.conf供dhcpserver使用。
6. 虚机向dhcp服务器发送请求时携带mac地址,dnsmasq收到请求后,将配置文件中对应mac地址的ip返回
1.5 libvirt driver
至此,新建的vm的所有数据信息(基本信息+网络)都已准备完毕。接下来就要调用libvirt的driver启动虚机了。调用的函数为spawn。
def spawn(self, context, instance, image_meta, injected_files,admin_password, network_info=None, block_device_info=None):
“””
代码位置:/opt/stack/nova/nova/virt/libvirt/driver.pyà1245
“””
1. 转换成libvirt所需的xml
xml = self.to_xml(instance, network_info, image_meta,block_device_info=block_device_info)
生成的xml为
<domain type="qemu">
<uuid>b110ed3b-9cc3-4d30-b433-a71090166b2c</uuid>
<name>instance-00000002</name>
<memory>524288</memory>
<vcpu>1</vcpu>
<os>
<type>hvm</type>
<kernel>/opt/stack/data/nova/instances/instance-00000002/kernel</kernel>
<initrd>/opt/stack/data/nova/instances/instance-00000002/ramdisk</initrd>
<cmdline>root=/dev/vdaconsole=ttyS0</cmdline>
</os>
<features>
<acpi/>
</features>
<clockoffset="utc"/>
<devices>
<disk type="file"device="cdrom">
<drivername="qemu"/>
<targetbus="ide" dev="hdb"/>
</disk>
<disk type="file"device="disk">
<drivername="qemu" type="qcow2" cache="writeback"/>
<source file="/opt/stack/data/nova/instances/instance-00000002/disk"/>
<targetbus="virtio" dev="hda"/>
</disk>
<interfacetype="bridge">
<macaddress="fa:16:3e:47:ef:94"/>
<modeltype="virtio"/>
<sourcebridge="br100"/>
<filterreffilter="nova-instance-instance-00000002-fa163e47ef94">
<parametername="IP" value="10.1.0.4"/>
<parametername="DHCPSERVER" value="10.1.0.3"/>
<parametername="PROJNET" value="10.1.0.0"/>
<parametername="PROJMASK" value="255.255.0.0"/>
</filterref>
</interface>
<serialtype="file">
<source path="/opt/stack/data/nova/instances/instance-00000002/console.log"/>
</serial>
<serialtype="pty"/>
<inputtype="tablet" bus="usb"/>
<graphicstype="vnc" autoport="yes" keymap="en-us"listen="0.0.0.0"/>
<video>
<modeltype="vga"/>
</video>
</devices>
</domain>
2. 准备镜像(将镜像拷贝到宿主机)
self._create_image(context, instance, xml, network_info=network_info, block_device_info=block_device_info,files=injected_files, admin_pass=admin_password)
详细请见1.6 节
3. 利用libvirt api创建domain,并将iptalbes规则应用到vm。
self._create_domain_and_network(xml, instance, network_info,block_device_info)
1) self.plug_vifs(instance,network_info)
2) self.firewall_driver.setup_basic_filtering(instance,network_info)
Basic_filter=[nova_base]
3) self.firewall_driver.prepare_instance_filter(instance,network_info)
² ipv4_rules
² ['-m state --state INVALID -jDROP', '-m state --state ESTABLISHED,RELATED -j ACCEPT', '-j $provider', u'-s10.1.0.3 -p udp --sport 67 --dport 68 -j ACCEPT', u'-s 10.1.0.0/16 -j ACCEPT',u'-j ACCEPT -p icmp -s 0.0.0.0/0', u'-j ACCEPT -p tcp --dport 80 -s 0.0.0.0/0',u'-j ACCEPT -p tcp --dport 22 -s 0.0.0.0/0', u'-j ACCEPT -p tcp --dport 3389 -s0.0.0.0/0', u'-j ACCEPT -p tcp --dport 50070 -s 0.0.0.0/0', u'-j ACCEPT -p tcp--dport 50030 -s 0.0.0.0/0', '-j $sg-fallback']
4) domain =self._create_domain(xml)
5) self.firewall_driver.apply_instance_filter(instance,network_info)
6) vm建成!!!!
1.6 Image
1.6.1 create_image
libvirtdriver把libvirt_xml创建好之后,我们发现对应的kernel,ramdisk和disk文件还没有。这时候就要开始创建镜像了。具体流程如下:
def _create_image(self, context, instance, libvirt_xml, suffix='',disk_images=None, network_info=None, block_device_info=None, files=None,admin_pass=None):
“””
代码位置:/opt/stack/nova/nova/virt/libvirt/driver.py 1428
”””
1. 定义basepath函数
def basepath(fname='', suffix=suffix):
returnos.path.join(FLAGS.instances_path,
instance['name'],
fname + suffix)
returnos.path.join(FLAGS.instances_path,
instance['name'],
fname + suffix)
FLAGS.instance_path=/opt/stack/data/nova/instances
2. 确保instance_path存在
utils.ensure_tree(basepath(suffix=''))
3. 将生成的libvirt_xml写入文件
libvirt_utils.write_to_file(basepath('libvirt.xml'),libvirt_xml)
/opt/stack/data/nova/instances/instance-0000000a/libvirt.xml
4. 修改console.log权限和写文件(若没有则创建)
/opt/stack/data/nova/instances/instance-0000000a/console.log
5. 获取ramdisk,kernel和disk文件(详见1.6.2节相应方法)
disk_images = {'image_id': instance['image_ref'],
'kernel_id': instance['kernel_id'],
'ramdisk_id': instance['ramdisk_id']}
- 获取kernel(调用imagebackend.py文件中Raw类相应的方法)
注:libvirt_utils.fetch_image是从glance下载镜像
raw('kernel').cache(fetch_func=libvirt_utils.fetch_image,
context=context,
filename=fname,
image_id=disk_images['kernel_id'],
user_id=instance['user_id'],
project_id=instance['project_id'])
fname =disk_images['kernel_id']->adaf51fe-c235-40b6-8aa7-80216d42303c
- 获取ramdisk(调用imagebackend.py文件中Raw类相应的方法)
raw('ramdisk').cache(fetch_func=libvirt_utils.fetch_image,
context=context,
filename=fname,
image_id=disk_images['ramdisk_id'],
user_id=instance['user_id'],
project_id=instance['project_id'])
fname = disk_images['ramdisk_id']->f9216b02-8e27-44da-b159-8d64401a16f2
- 获取disk(调用imagebackend.py文件中Qcow2类相应的方法)
image('disk').cache(fetch_func=libvirt_utils.fetch_image,
context=context,
filename=root_fname,
size=size,
image_id=disk_images['image_id'],
user_id=instance['user_id'],
project_id=instance['project_id'])
root_fname = hashlib.sha1(str(disk_images['image_id'])).hexdigest()
1.6.2 virt/libvirt/imagebackend
该文件定义了基类Image,Raw和Qcow2为子类。基类Image定义cache方法,主要功能是生成base路径(如:/opt/stack/data/nova/instances/_base/adaf51fe-c235…7-0216d42303c),调用子类create_image方法创建镜像文件(kernel,ramdisk,disk)。
注:子类的create_image方法第一个参数prepare_template被设置为基类Image中 cache的内部方法call_if_not_exists,该方法判断target文件是否存在,若不存在则调用libvirt_utils.fetch_image(详见1.6.3的fetch_image方法) 下载镜像文件。
class Image(object):
def cache(self, fetch_func, filename,size=None, *args, **kwargs):
“””
代码位置:/opt/stack/nova/nova/virt/libvirt/imagebackend.pyà105
self.path=/opt/stack/data/nova/instances/instance-0000000c/kernel
base=/opt/stack/data/nova/instances/_base/adaf51fe-c235-40b6-8aa7-0216d42303c
”””
@utils.synchronized(filename,external=True, lock_path=self.lock_path)
defcall_if_not_exists(target, *args, **kwargs):
“””
该方法作为子类中create_image方法的参数prepare_template
作用是若target文件不存在,则调用fetch_fuc获取文件
本例中fetch_fuc= libvirt_utils.fetch_image,即从glance下载镜像
”””
if notos.path.exists(target):
fetch_func(target=target,*args, **kwargs)
if not os.path.exists(self.path):
base_dir= os.path.join(FLAGS.instances_path, '_base')
if not os.path.exists(base_dir):
utils.ensure_tree(base_dir)
base = os.path.join(base_dir, filename)
#调用子类的create_image方法,prepare_template=call_if_not_exists
self.create_image(call_if_not_exists, base, size, *args, **kwargs)
class Raw(Image):
def __init__(self,instance, name):
super(Raw, self).__init__("file", "raw",is_block_dev=False)
self.path=os.path.join(FLAGS.instances_path, instance, name)
def create_image(self, prepare_template, base, size, *args, **kwargs):
“””
代码位置:/opt/stack/nova/nova/virt/libvirt/imagebackend.pyà139
prepare_template = call_if_not_exists
base=/opt/stack/data/nova/instances/_base/adaf51fe-c235-…6-8aa7-0216d42303c
self.path=/opt/stack/data/nova/instances/instance-0000000c/kernel
”””
@utils.synchronized(base,external=True, lock_path=self.lock_path)
def copy_raw_image(base,target, size):
“””
该方法利用cp,将base目录下的文件拷贝到target
”””
libvirt_utils.copy_image(base,target)à详见1.6.3节copy_image方法
if size:
disk.extend(target, size)
generating = 'image_id' not in kwargs
if generating:
#Generating image in place
prepare_template(target=self.path, *args, **kwargs)
else:
#准备base的kernel或ramdisk镜像,确保base目录下的文件存在
prepare_template(target=base,*args, **kwargs)# call_if_not_exists
with utils.remove_path_on_error(self.path):
class Qcow2(Image):# 将base文件拷贝到instance目录下
copy_raw_image(base,self.path, size)
def __init__(self,instance, name):
super(Qcow2, self).__init__("file","qcow2", is_block_dev=False)
self.path=os.path.join(FLAGS.instances_path, instance, name)
def create_image(self, prepare_template, base, size, *args, **kwargs):
“””
代码位置:/opt/stack/nova/nova/virt/libvirt/imagebackend.pyà163
self.path=/opt/stack/data/nova/instances/instance-0000000c/disk
base=/opt/stack/data/nova/instances/_base/dd0ce6ec1af…eef7867f1063c9b5b028db
”””
@utils.synchronized(base, external=True,lock_path=self.lock_path)
def copy_qcow2_image(base, target, size):
“””
该方法利用qemu-img命令创建镜像,并设置backing_file
qemu-img create –f disk_format –o preallocation=metadata –obacking_file=base target
”””
qcow2_base = base
if size:
size_gb = size / (1024 * 1024 *1024)
qcow2_base += '_%d' % size_gb
if notos.path.exists(qcow2_base):
withutils.remove_path_on_error(qcow2_base):
libvirt_utils.copy_image(base, qcow2_base)
disk.extend(qcow2_base,size)
#准备base的disk镜像,确保base目录下的文件存在libvirt_utils.create_cow_image(qcow2_base,target)
->详见1.6.3节create_cow_image方法
prepare_template(target=base, *args, **kwargs)
withutils.remove_path_on_error(self.path):
# 利用qemu-img命令创建disk文件,backing_file为base文件
copy_qcow2_image(base,self.path, size)
1.6.3 virt/libvirt/utils.py
def fetch_image(context,target, image_id, user_id, project_id):
“””
代码位置:/opt/stack/nova/nova/virt/libvirt/utils.pyà397
”””
#该函数调用/opt/stack/nova/nova/virt/images.py中的fetch_to_raw方法(见1.6.4节)
images.fetch_to_raw(context, image_id, target, user_id, project_id)
….
def copy_image(src, dest,host=None):
“””
代码位置:/opt/stack/nova/nova/virt/libvirt/utils.pyà215
函数功能:利用cp或rsync命令拷贝镜像
”””
if not host:
execute('cp', src, dest)
else:
try:
execute('rsync', '--sparse', '--compress', '--dry-run', src,dest)
except exception.ProcessExecutionError:
execute('scp',src, dest)
else:
execute('rsync', '--sparse', '--compress', src, dest)
def create_cow_image(backing_file,path):
“””
代码位置:/opt/stack/nova/nova/virt/libvirt/utils.pyà84
函数功能:调用qemu-img命令创建镜像文件
”””
execute('qemu-img','create', '-f', 'qcow2', '-o preallocation=metadata', '-o',
'backing_file=%s'% backing_file, path)
1.6.4 virt/images.py
def fetch_to_raw(context,image_href, path, user_id, project_id):
“””
代码位置:/opt/stack/nova/nova/virt/images.pyà75
函数功能:调用fetch函数
”””
path_tmp = "%s.part" % path
fetch(context, image_href, path_tmp, user_id, project_id)
def fetch(context,image_href, path, _user_id, _project_id):
“””
代码位置:/opt/stack/nova/nova/virt/images.pyà63
函数功能:从glance下载镜像文件
”””
(image_service, image_id) =glance.get_remote_image_service(context, image_href)
with utils.remove_path_on_error(path):
with open(path, "wb") as image_file:
image_service.download(context, image_id, image_file)
- nova 创建虚拟机流程
- NOVA 创建虚拟机流程
- openstack.nova.manager创建虚拟机流程(run_instance)
- openstack.nova.manager创建虚拟机流程
- 【openstack】Nova创建虚拟机流程1
- 【openstack】Nova创建虚拟机流程2 -scheduler
- 【openstack】Nova创建虚拟机流程3-compute
- openstack nova 创建虚拟机流程 liberty版本
- OpenStack Nova 虚拟机创建流程分析
- Nova API服务 之 创建虚拟机流程(1)
- Nova API服务 之 创建虚拟机流程(2)
- Nova API服务之 创建虚拟机流程(3)
- openstack Nova分析之 创建虚拟机流程(4)
- OpenStack中nova组件创建虚拟机的源码流程
- nova 虚拟机创建过程
- nova 创建虚拟机
- nova创建instance流程
- openstack:nova中“从镜像启动(创建一个新卷)”创建虚拟机的流程
- Unity手游开发与实战
- 找最大的k个数
- swust 2014届选拔赛 题解
- Linux环境进程间通信(三)消息队列
- 资深HR总结六项面试应对方法
- nova 创建虚拟机流程
- 15个提升App用户体验的步骤(上)
- 在VS里面写SQL语句将数据插入到Oracle里面
- Why Link Prediction?
- DRM in Android
- Ajax实现--javascript
- android体系结构介绍
- 【ShaderToy】水彩画
- [leetcode][math] Ugly Number