Merge lp:~sateesh-chodapuneedi/nova/esx-multi-nic into lp:~hudson-openstack/nova/milestone-proposed

Proposed by Vish Ishaya
Status: Merged
Approved by: Vish Ishaya
Approved revision: 1527
Merged at revision: 1166
Proposed branch: lp:~sateesh-chodapuneedi/nova/esx-multi-nic
Merge into: lp:~hudson-openstack/nova/milestone-proposed
Diff against target: 440 lines (+127/-112)
6 files modified
nova/tests/vmwareapi/stubs.py (+0/-2)
nova/virt/vmwareapi/fake.py (+1/-1)
nova/virt/vmwareapi/vif.py (+11/-16)
nova/virt/vmwareapi/vm_util.py (+12/-16)
nova/virt/vmwareapi/vmops.py (+63/-47)
tools/esx/guest_tool.py (+40/-30)
To merge this branch: bzr merge lp:~sateesh-chodapuneedi/nova/esx-multi-nic
Reviewer Review Type Date Requested Status
OpenStack release team Pending
Review via email: mp+75368@code.launchpad.net

Description of the change

Multi-NIC support for vmwareapi virt driver in nova.
Does injection of Multi-NIC information to instances with Operating system flavors Ubuntu, Windows and RHEL.
vmwareapi virt driver now relies on calls to network manager instead of nova db calls for network configuration information of instance.
Re-oranized VMWareVlanBridgeDriver and added session parmeter to methods to use existing session. Also removed session creation code as session comes as argument.
Added check for flat_inject flag before attempting an inject operation.

This branch resolves the following bugs:
  Bug #831497 in OpenStack Compute (nova): "Instance spawn operation fails on ESXi compute node"
  https://bugs.launchpad.net/nova/+bug/831497
  Bug #839383 in OpenStack Compute (nova): "ESX(i) VIFs and mac addresses"
  https://bugs.launchpad.net/nova/+bug/839383

To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'nova/tests/vmwareapi/stubs.py'
--- nova/tests/vmwareapi/stubs.py 2011-07-27 00:40:50 +0000
+++ nova/tests/vmwareapi/stubs.py 2011-09-14 15:30:11 +0000
@@ -47,7 +47,5 @@
47 stubs.Set(vmware_images, 'upload_image', fake.fake_upload_image)47 stubs.Set(vmware_images, 'upload_image', fake.fake_upload_image)
48 stubs.Set(vmwareapi_conn.VMWareAPISession, "_get_vim_object",48 stubs.Set(vmwareapi_conn.VMWareAPISession, "_get_vim_object",
49 fake_get_vim_object)49 fake_get_vim_object)
50 stubs.Set(vmwareapi_conn.VMWareAPISession, "_get_vim_object",
51 fake_get_vim_object)
52 stubs.Set(vmwareapi_conn.VMWareAPISession, "_is_vim_object",50 stubs.Set(vmwareapi_conn.VMWareAPISession, "_is_vim_object",
53 fake_is_vim_object)51 fake_is_vim_object)
5452
=== modified file 'nova/virt/vmwareapi/fake.py'
--- nova/virt/vmwareapi/fake.py 2011-09-12 15:00:09 +0000
+++ nova/virt/vmwareapi/fake.py 2011-09-14 15:30:11 +0000
@@ -409,7 +409,7 @@
409409
410def fake_get_network(*args, **kwargs):410def fake_get_network(*args, **kwargs):
411 """Fake get network."""411 """Fake get network."""
412 return [{'type': 'fake'}]412 return {'type': 'fake'}
413413
414414
415def fake_fetch_image(context, image, instance, **kwargs):415def fake_fetch_image(context, image, instance, **kwargs):
416416
=== modified file 'nova/virt/vmwareapi/vif.py'
--- nova/virt/vmwareapi/vif.py 2011-08-03 18:49:14 +0000
+++ nova/virt/vmwareapi/vif.py 2011-09-14 15:30:11 +0000
@@ -17,42 +17,35 @@
1717
18"""VIF drivers for VMWare."""18"""VIF drivers for VMWare."""
1919
20from nova import db
21from nova import exception20from nova import exception
22from nova import flags21from nova import flags
23from nova import log as logging22from nova import log as logging
24from nova import utils
25from nova.virt.vif import VIFDriver23from nova.virt.vif import VIFDriver
26from nova.virt.vmwareapi_conn import VMWareAPISession
27from nova.virt.vmwareapi import network_utils24from nova.virt.vmwareapi import network_utils
2825
2926
30LOG = logging.getLogger("nova.virt.vmwareapi.vif")27LOG = logging.getLogger("nova.virt.vmwareapi.vif")
3128
32FLAGS = flags.FLAGS29FLAGS = flags.FLAGS
30FLAGS['vmwareapi_vlan_interface'].SetDefault('vmnic0')
3331
3432
35class VMWareVlanBridgeDriver(VIFDriver):33class VMWareVlanBridgeDriver(VIFDriver):
36 """VIF Driver to setup bridge/VLAN networking using VMWare API."""34 """VIF Driver to setup bridge/VLAN networking using VMWare API."""
3735
38 def plug(self, instance, network, mapping):36 def plug(self, instance, network, mapping):
37 """Plug the VIF to specified instance using information passed.
38 Currently we are plugging the VIF(s) during instance creation itself.
39 We can use this method when we add support to add additional NIC to
40 an existing instance."""
41 pass
42
43 def ensure_vlan_bridge(self, session, network):
39 """Create a vlan and bridge unless they already exist."""44 """Create a vlan and bridge unless they already exist."""
40 vlan_num = network['vlan']45 vlan_num = network['vlan']
41 bridge = network['bridge']46 bridge = network['bridge']
42 bridge_interface = network['bridge_interface']47 vlan_interface = FLAGS.vmwareapi_vlan_interface
4348
44 # Open vmwareapi session
45 host_ip = FLAGS.vmwareapi_host_ip
46 host_username = FLAGS.vmwareapi_host_username
47 host_password = FLAGS.vmwareapi_host_password
48 if not host_ip or host_username is None or host_password is None:
49 raise Exception(_('Must specify vmwareapi_host_ip, '
50 'vmwareapi_host_username '
51 'and vmwareapi_host_password to use '
52 'connection_type=vmwareapi'))
53 session = VMWareAPISession(host_ip, host_username, host_password,
54 FLAGS.vmwareapi_api_retry_count)
55 vlan_interface = bridge_interface
56 # Check if the vlan_interface physical network adapter exists on the49 # Check if the vlan_interface physical network adapter exists on the
57 # host.50 # host.
58 if not network_utils.check_if_vlan_interface_exists(session,51 if not network_utils.check_if_vlan_interface_exists(session,
@@ -92,4 +85,6 @@
92 pgroup=pg_vlanid)85 pgroup=pg_vlanid)
9386
94 def unplug(self, instance, network, mapping):87 def unplug(self, instance, network, mapping):
88 """Cleanup operations like deleting port group if no instance
89 is associated with it."""
95 pass90 pass
9691
=== modified file 'nova/virt/vmwareapi/vm_util.py'
--- nova/virt/vmwareapi/vm_util.py 2011-07-27 00:40:50 +0000
+++ nova/virt/vmwareapi/vm_util.py 2011-09-14 15:30:11 +0000
@@ -39,8 +39,7 @@
3939
4040
41def get_vm_create_spec(client_factory, instance, data_store_name,41def get_vm_create_spec(client_factory, instance, data_store_name,
42 network_name="vmnet0",42 vif_infos, os_type="otherGuest"):
43 os_type="otherGuest", network_ref=None):
44 """Builds the VM Create spec."""43 """Builds the VM Create spec."""
45 config_spec = client_factory.create('ns0:VirtualMachineConfigSpec')44 config_spec = client_factory.create('ns0:VirtualMachineConfigSpec')
46 config_spec.name = instance.name45 config_spec.name = instance.name
@@ -61,14 +60,12 @@
61 config_spec.numCPUs = int(instance.vcpus)60 config_spec.numCPUs = int(instance.vcpus)
62 config_spec.memoryMB = int(instance.memory_mb)61 config_spec.memoryMB = int(instance.memory_mb)
6362
64 mac_address = None63 vif_spec_list = []
65 if instance['mac_addresses']:64 for vif_info in vif_infos:
66 mac_address = instance['mac_addresses'][0]['address']65 vif_spec = create_network_spec(client_factory, vif_info)
6766 vif_spec_list.append(vif_spec)
68 nic_spec = create_network_spec(client_factory,67
69 network_name, mac_address)68 device_config_spec = vif_spec_list
70
71 device_config_spec = [nic_spec]
7269
73 config_spec.deviceChange = device_config_spec70 config_spec.deviceChange = device_config_spec
74 return config_spec71 return config_spec
@@ -93,8 +90,7 @@
93 return virtual_device_config90 return virtual_device_config
9491
9592
96def create_network_spec(client_factory, network_name, mac_address,93def create_network_spec(client_factory, vif_info):
97 network_ref=None):
98 """94 """
99 Builds a config spec for the addition of a new network95 Builds a config spec for the addition of a new network
100 adapter to the VM.96 adapter to the VM.
@@ -109,6 +105,9 @@
109 # NOTE(asomya): Only works on ESXi if the portgroup binding is set to105 # NOTE(asomya): Only works on ESXi if the portgroup binding is set to
110 # ephemeral. Invalid configuration if set to static and the NIC does106 # ephemeral. Invalid configuration if set to static and the NIC does
111 # not come up on boot if set to dynamic.107 # not come up on boot if set to dynamic.
108 network_ref = vif_info['network_ref']
109 network_name = vif_info['network_name']
110 mac_address = vif_info['mac_address']
112 backing = None111 backing = None
113 if (network_ref and112 if (network_ref and
114 network_ref['type'] == "DistributedVirtualPortgroup"):113 network_ref['type'] == "DistributedVirtualPortgroup"):
@@ -295,11 +294,8 @@
295 return config_spec294 return config_spec
296295
297296
298def get_machine_id_change_spec(client_factory, mac, ip_addr, netmask,297def get_machine_id_change_spec(client_factory, machine_id_str):
299 gateway, broadcast, dns):
300 """Builds the machine id change config spec."""298 """Builds the machine id change config spec."""
301 machine_id_str = "%s;%s;%s;%s;%s;%s" % (mac, ip_addr, netmask,
302 gateway, broadcast, dns)
303 virtual_machine_config_spec = \299 virtual_machine_config_spec = \
304 client_factory.create('ns0:VirtualMachineConfigSpec')300 client_factory.create('ns0:VirtualMachineConfigSpec')
305301
306302
=== modified file 'nova/virt/vmwareapi/vmops.py'
--- nova/virt/vmwareapi/vmops.py 2011-09-12 15:00:09 +0000
+++ nova/virt/vmwareapi/vmops.py 2011-09-14 15:30:11 +0000
@@ -27,7 +27,6 @@
27import uuid27import uuid
2828
29from nova import context as nova_context29from nova import context as nova_context
30from nova import db
31from nova import exception30from nova import exception
32from nova import flags31from nova import flags
33from nova import log as logging32from nova import log as logging
@@ -111,22 +110,6 @@
111 client_factory = self._session._get_vim().client.factory110 client_factory = self._session._get_vim().client.factory
112 service_content = self._session._get_vim().get_service_content()111 service_content = self._session._get_vim().get_service_content()
113112
114 network = db.network_get_by_instance(nova_context.get_admin_context(),
115 instance['id'])
116
117 net_name = network['bridge']
118
119 def _check_if_network_bridge_exists():
120 network_ref = \
121 network_utils.get_network_with_the_name(self._session,
122 net_name)
123 if network_ref is None:
124 raise exception.NetworkNotFoundForBridge(bridge=net_name)
125 return network_ref
126
127 self.plug_vifs(instance, network_info)
128 network_obj = _check_if_network_bridge_exists()
129
130 def _get_datastore_ref():113 def _get_datastore_ref():
131 """Get the datastore list and choose the first local storage."""114 """Get the datastore list and choose the first local storage."""
132 data_stores = self._session._call_method(vim_util, "get_objects",115 data_stores = self._session._call_method(vim_util, "get_objects",
@@ -182,11 +165,36 @@
182165
183 vm_folder_mor, res_pool_mor = _get_vmfolder_and_res_pool_mors()166 vm_folder_mor, res_pool_mor = _get_vmfolder_and_res_pool_mors()
184167
168 def _check_if_network_bridge_exists(network_name):
169 network_ref = \
170 network_utils.get_network_with_the_name(self._session,
171 network_name)
172 if network_ref is None:
173 raise exception.NetworkNotFoundForBridge(bridge=network_name)
174 return network_ref
175
176 def _get_vif_infos():
177 vif_infos = []
178 for (network, mapping) in network_info:
179 mac_address = mapping['mac']
180 network_name = network['bridge']
181 if mapping.get('should_create_vlan'):
182 network_ref = self._vif_driver.ensure_vlan_bridge(
183 self._session, network)
184 else:
185 network_ref = _check_if_network_bridge_exists(network_name)
186 vif_infos.append({'network_name': network_name,
187 'mac_address': mac_address,
188 'network_ref': network_ref,
189 })
190 return vif_infos
191
192 vif_infos = _get_vif_infos()
193
185 # Get the create vm config spec194 # Get the create vm config spec
186 config_spec = vm_util.get_vm_create_spec(195 config_spec = vm_util.get_vm_create_spec(
187 client_factory, instance,196 client_factory, instance,
188 data_store_name, net_name, os_type,197 data_store_name, vif_infos, os_type)
189 network_obj)
190198
191 def _execute_create_vm():199 def _execute_create_vm():
192 """Create VM on ESX host."""200 """Create VM on ESX host."""
@@ -204,8 +212,10 @@
204212
205 _execute_create_vm()213 _execute_create_vm()
206214
207 # Set the machine id for the VM for setting the IP215 # Set the machine.id parameter of the instance to inject
208 self._set_machine_id(client_factory, instance)216 # the NIC configuration inside the VM
217 if FLAGS.flat_injected:
218 self._set_machine_id(client_factory, instance, network_info)
209219
210 # Naming the VM files in correspondence with the VM instance name220 # Naming the VM files in correspondence with the VM instance name
211 # The flat vmdk file name221 # The flat vmdk file name
@@ -718,39 +728,45 @@
718 """Return link to instance's ajax console."""728 """Return link to instance's ajax console."""
719 return 'http://fakeajaxconsole/fake_url'729 return 'http://fakeajaxconsole/fake_url'
720730
721 def _set_machine_id(self, client_factory, instance):731 def _set_machine_id(self, client_factory, instance, network_info):
722 """732 """
723 Set the machine id of the VM for guest tools to pick up and change733 Set the machine id of the VM for guest tools to pick up and reconfigure
724 the IP.734 the network interfaces.
725 """735 """
726 admin_context = nova_context.get_admin_context()
727 vm_ref = self._get_vm_ref_from_the_name(instance.name)736 vm_ref = self._get_vm_ref_from_the_name(instance.name)
728 if vm_ref is None:737 if vm_ref is None:
729 raise exception.InstanceNotFound(instance_id=instance.id)738 raise exception.InstanceNotFound(instance_id=instance.id)
730 network = db.network_get_by_instance(nova_context.get_admin_context(),739
731 instance['id'])740 machine_id_str = ''
732 mac_address = None741 for (network, info) in network_info:
733 if instance['mac_addresses']:742 # TODO(vish): add support for dns2
734 mac_address = instance['mac_addresses'][0]['address']743 # TODO(sateesh): add support for injection of ipv6 configuration
735744 ip_v4 = ip_v6 = None
736 net_mask = network["netmask"]745 if 'ips' in info and len(info['ips']) > 0:
737 gateway = network["gateway"]746 ip_v4 = info['ips'][0]
738 broadcast = network["broadcast"]747 if 'ip6s' in info and len(info['ip6s']) > 0:
739 # TODO(vish): add support for dns2748 ip_v6 = info['ip6s'][0]
740 dns = network["dns1"]749 if len(info['dns']) > 0:
741750 dns = info['dns'][0]
742 addresses = db.instance_get_fixed_addresses(admin_context,751 else:
743 instance['id'])752 dns = ''
744 ip_addr = addresses[0] if addresses else None753
754 interface_str = "%s;%s;%s;%s;%s;%s" % \
755 (info['mac'],
756 ip_v4 and ip_v4['ip'] or '',
757 ip_v4 and ip_v4['netmask'] or '',
758 info['gateway'],
759 info['broadcast'],
760 dns)
761 machine_id_str = machine_id_str + interface_str + '#'
745762
746 machine_id_change_spec = \763 machine_id_change_spec = \
747 vm_util.get_machine_id_change_spec(client_factory, mac_address,764 vm_util.get_machine_id_change_spec(client_factory, machine_id_str)
748 ip_addr, net_mask, gateway,765
749 broadcast, dns)
750 LOG.debug(_("Reconfiguring VM instance %(name)s to set the machine id "766 LOG.debug(_("Reconfiguring VM instance %(name)s to set the machine id "
751 "with ip - %(ip_addr)s") %767 "with ip - %(ip_addr)s") %
752 ({'name': instance.name,768 ({'name': instance.name,
753 'ip_addr': ip_addr}))769 'ip_addr': ip_v4['ip']}))
754 reconfig_task = self._session._call_method(self._session._get_vim(),770 reconfig_task = self._session._call_method(self._session._get_vim(),
755 "ReconfigVM_Task", vm_ref,771 "ReconfigVM_Task", vm_ref,
756 spec=machine_id_change_spec)772 spec=machine_id_change_spec)
@@ -758,7 +774,7 @@
758 LOG.debug(_("Reconfigured VM instance %(name)s to set the machine id "774 LOG.debug(_("Reconfigured VM instance %(name)s to set the machine id "
759 "with ip - %(ip_addr)s") %775 "with ip - %(ip_addr)s") %
760 ({'name': instance.name,776 ({'name': instance.name,
761 'ip_addr': ip_addr}))777 'ip_addr': ip_v4['ip']}))
762778
763 def _get_datacenter_name_and_ref(self):779 def _get_datacenter_name_and_ref(self):
764 """Get the datacenter name and the reference."""780 """Get the datacenter name and the reference."""
765781
=== modified file 'tools/esx/guest_tool.py'
--- tools/esx/guest_tool.py 2011-06-27 18:41:07 +0000
+++ tools/esx/guest_tool.py 2011-09-14 15:30:11 +0000
@@ -81,28 +81,34 @@
8181
82def _parse_network_details(machine_id):82def _parse_network_details(machine_id):
83 """83 """
84 Parse the machine.id field to get MAC, IP, Netmask and Gateway fields84 Parse the machine_id to get MAC, IP, Netmask and Gateway fields per NIC.
85 machine.id is of the form MAC;IP;Netmask;Gateway;Broadcast;DNS1,DNS285 machine_id is of the form ('NIC_record#NIC_record#', '')
86 where ';' is the separator.86 Each of the NIC will have record NIC_record in the form
87 'MAC;IP;Netmask;Gateway;Broadcast;DNS' where ';' is field separator.
88 Each record is separated by '#' from next record.
87 """89 """
90 logging.debug(_("Received machine_id from vmtools : %s") % machine_id[0])
88 network_details = []91 network_details = []
89 if machine_id[1].strip() == "1":92 if machine_id[1].strip() == "1":
90 pass93 pass
91 else:94 else:
92 network_info_list = machine_id[0].split(';')95 for machine_id_str in machine_id[0].split('#'):
93 assert len(network_info_list) % 6 == 096 network_info_list = machine_id_str.split(';')
94 no_grps = len(network_info_list) / 697 if len(network_info_list) % 6 != 0:
95 i = 098 break
96 while i < no_grps:99 no_grps = len(network_info_list) / 6
97 k = i * 6100 i = 0
98 network_details.append((101 while i < no_grps:
99 network_info_list[k].strip().lower(),102 k = i * 6
100 network_info_list[k + 1].strip(),103 network_details.append((
101 network_info_list[k + 2].strip(),104 network_info_list[k].strip().lower(),
102 network_info_list[k + 3].strip(),105 network_info_list[k + 1].strip(),
103 network_info_list[k + 4].strip(),106 network_info_list[k + 2].strip(),
104 network_info_list[k + 5].strip().split(',')))107 network_info_list[k + 3].strip(),
105 i += 1108 network_info_list[k + 4].strip(),
109 network_info_list[k + 5].strip().split(',')))
110 i += 1
111 logging.debug(_("NIC information from vmtools : %s") % network_details)
106 return network_details112 return network_details
107113
108114
@@ -279,6 +285,7 @@
279285
280286
281def _set_rhel_networking(network_details=None):287def _set_rhel_networking(network_details=None):
288 """Set IPv4 network settings for RHEL distros."""
282 network_details = network_details or []289 network_details = network_details or []
283 all_dns_servers = []290 all_dns_servers = []
284 for network_detail in network_details:291 for network_detail in network_details:
@@ -320,31 +327,33 @@
320327
321328
322def _set_ubuntu_networking(network_details=None):329def _set_ubuntu_networking(network_details=None):
330 """Set IPv4 network settings for Ubuntu."""
323 network_details = network_details or []331 network_details = network_details or []
324 """ Set IPv4 network settings for Ubuntu """
325 all_dns_servers = []332 all_dns_servers = []
326 for network_detail in network_details:333 interface_file_name = '/etc/network/interfaces'
334 # Remove file
335 os.remove(interface_file_name)
336 # Touch file
337 _execute(['touch', interface_file_name])
338 interface_file = open(interface_file_name, 'w')
339 for device, network_detail in enumerate(network_details):
327 mac_address, ip_address, subnet_mask, gateway, broadcast,\340 mac_address, ip_address, subnet_mask, gateway, broadcast,\
328 dns_servers = network_detail341 dns_servers = network_detail
329 all_dns_servers.extend(dns_servers)342 all_dns_servers.extend(dns_servers)
330 adapter_name, current_ip_address = \343 adapter_name, current_ip_address = \
331 _get_linux_adapter_name_and_ip_address(mac_address)344 _get_linux_adapter_name_and_ip_address(mac_address)
332345
333 if adapter_name and not ip_address == current_ip_address:346 if adapter_name:
334 interface_file_name = \
335 '/etc/network/interfaces'
336 # Remove file
337 os.remove(interface_file_name)
338 # Touch file
339 _execute(['touch', interface_file_name])
340 interface_file = open(interface_file_name, 'w')
341 interface_file.write('\nauto %s' % adapter_name)347 interface_file.write('\nauto %s' % adapter_name)
342 interface_file.write('\niface %s inet static' % adapter_name)348 interface_file.write('\niface %s inet static' % adapter_name)
343 interface_file.write('\nbroadcast %s' % broadcast)349 interface_file.write('\nbroadcast %s' % broadcast)
344 interface_file.write('\ngateway %s' % gateway)350 interface_file.write('\ngateway %s' % gateway)
345 interface_file.write('\nnetmask %s' % subnet_mask)351 interface_file.write('\nnetmask %s' % subnet_mask)
346 interface_file.write('\naddress %s' % ip_address)352 interface_file.write('\naddress %s\n' % ip_address)
347 interface_file.close()353 logging.debug(_("Successfully configured NIC %d with "
354 "NIC info %s") % (device, network_detail))
355 interface_file.close()
356
348 if all_dns_servers:357 if all_dns_servers:
349 dns_file_name = "/etc/resolv.conf"358 dns_file_name = "/etc/resolv.conf"
350 os.remove(dns_file_name)359 os.remove(dns_file_name)
@@ -355,7 +364,8 @@
355 for dns_server in unique_entries:364 for dns_server in unique_entries:
356 dns_file.write("\nnameserver %s" % dns_server)365 dns_file.write("\nnameserver %s" % dns_server)
357 dns_file.close()366 dns_file.close()
358 print "\nRestarting networking....\n"367
368 logging.debug(_("Restarting networking....\n"))
359 _execute(['/etc/init.d/networking', 'restart'])369 _execute(['/etc/init.d/networking', 'restart'])
360370
361371

Subscribers

People subscribed via source and target branches