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

Proposed by Sateesh
Status: Merged
Approved by: Dan Prince
Approved revision: 1527
Merged at revision: 1568
Proposed branch: lp:~sateesh-chodapuneedi/nova/esx-multi-nic
Merge into: lp:~hudson-openstack/nova/trunk
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
Dan Prince (community) Approve
Vish Ishaya (community) Approve
Review via email: mp+74055@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.
Revision history for this message
Vish Ishaya (vishvananda) wrote :

Awesome work on this! It will be great to have esx working properly again. Minor nit:

63 - bridge_interface = network['bridge_interface']
64 + vlan_interface = FLAGS.vmwareapi_vlan_interface

can we just use the global vlan interface here?

review: Needs Information
Revision history for this message
Sateesh (sateesh-chodapuneedi) wrote :

@Vish thanks for the review.

> 63 - bridge_interface = network['bridge_interface']
> 64 + vlan_interface = FLAGS.vmwareapi_vlan_interface
>
> can we just use the global vlan interface here?

I choose to use separate flag because vlan_interface is not being used in the current code base (revision 1526), also post multi-nic nova code started using bridge_interface in networks table rather than depending on this flag. From the information I have, it seems to me that this flag is going to become stale. So I thought of having a separate flag specific vmwareapi virt driver which deals with it's specific case. Even if vlan_interface flag gets removed no functionality breakage occur in vmwareapi virt driver. So trying to keep this flag modular (or module specific).
Also ESX(i) names it NIC with prefix 'vmnic', different from other systems that use prefix 'eth'. So I thought if we classify the flag by it's value, it becomes specific to vmware subset.

Revision history for this message
Vish Ishaya (vishvananda) wrote :

We were actually planning on adding the flag back as an override. It is possible that the interface specified in the table is incorrect for some hosts. For example if you have two hosts, one using eth0 and the other using eth1. But this is a minor issue that can be fixed later. I'm happy leaving this as is for now.

review: Approve
Revision history for this message
Dan Prince (dan-prince) wrote :

Looks good to me.

review: Approve
Revision history for this message
Sateesh (sateesh-chodapuneedi) wrote :

Thanks Vish and Dan for your reviews.

Revision history for this message
Sateesh (sateesh-chodapuneedi) wrote :

Thanks Vish and Dan for your reviews.

~Sateesh

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-05 07:38:25 +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-07-27 00:40:50 +0000
+++ nova/virt/vmwareapi/fake.py 2011-09-05 07:38:25 +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(image, instance, **kwargs):415def fake_fetch_image(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-05 07:38:25 +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-05 07:38:25 +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-07-29 21:58:27 +0000
+++ nova/virt/vmwareapi/vmops.py 2011-09-05 07:38:25 +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
@@ -716,39 +726,45 @@
716 """Return link to instance's ajax console."""726 """Return link to instance's ajax console."""
717 return 'http://fakeajaxconsole/fake_url'727 return 'http://fakeajaxconsole/fake_url'
718728
719 def _set_machine_id(self, client_factory, instance):729 def _set_machine_id(self, client_factory, instance, network_info):
720 """730 """
721 Set the machine id of the VM for guest tools to pick up and change731 Set the machine id of the VM for guest tools to pick up and reconfigure
722 the IP.732 the network interfaces.
723 """733 """
724 admin_context = nova_context.get_admin_context()
725 vm_ref = self._get_vm_ref_from_the_name(instance.name)734 vm_ref = self._get_vm_ref_from_the_name(instance.name)
726 if vm_ref is None:735 if vm_ref is None:
727 raise exception.InstanceNotFound(instance_id=instance.id)736 raise exception.InstanceNotFound(instance_id=instance.id)
728 network = db.network_get_by_instance(nova_context.get_admin_context(),737
729 instance['id'])738 machine_id_str = ''
730 mac_address = None739 for (network, info) in network_info:
731 if instance['mac_addresses']:740 # TODO(vish): add support for dns2
732 mac_address = instance['mac_addresses'][0]['address']741 # TODO(sateesh): add support for injection of ipv6 configuration
733742 ip_v4 = ip_v6 = None
734 net_mask = network["netmask"]743 if 'ips' in info and len(info['ips']) > 0:
735 gateway = network["gateway"]744 ip_v4 = info['ips'][0]
736 broadcast = network["broadcast"]745 if 'ip6s' in info and len(info['ip6s']) > 0:
737 # TODO(vish): add support for dns2746 ip_v6 = info['ip6s'][0]
738 dns = network["dns1"]747 if len(info['dns']) > 0:
739748 dns = info['dns'][0]
740 addresses = db.instance_get_fixed_addresses(admin_context,749 else:
741 instance['id'])750 dns = ''
742 ip_addr = addresses[0] if addresses else None751
752 interface_str = "%s;%s;%s;%s;%s;%s" % \
753 (info['mac'],
754 ip_v4 and ip_v4['ip'] or '',
755 ip_v4 and ip_v4['netmask'] or '',
756 info['gateway'],
757 info['broadcast'],
758 dns)
759 machine_id_str = machine_id_str + interface_str + '#'
743760
744 machine_id_change_spec = \761 machine_id_change_spec = \
745 vm_util.get_machine_id_change_spec(client_factory, mac_address,762 vm_util.get_machine_id_change_spec(client_factory, machine_id_str)
746 ip_addr, net_mask, gateway,763
747 broadcast, dns)
748 LOG.debug(_("Reconfiguring VM instance %(name)s to set the machine id "764 LOG.debug(_("Reconfiguring VM instance %(name)s to set the machine id "
749 "with ip - %(ip_addr)s") %765 "with ip - %(ip_addr)s") %
750 ({'name': instance.name,766 ({'name': instance.name,
751 'ip_addr': ip_addr}))767 'ip_addr': ip_v4['ip']}))
752 reconfig_task = self._session._call_method(self._session._get_vim(),768 reconfig_task = self._session._call_method(self._session._get_vim(),
753 "ReconfigVM_Task", vm_ref,769 "ReconfigVM_Task", vm_ref,
754 spec=machine_id_change_spec)770 spec=machine_id_change_spec)
@@ -756,7 +772,7 @@
756 LOG.debug(_("Reconfigured VM instance %(name)s to set the machine id "772 LOG.debug(_("Reconfigured VM instance %(name)s to set the machine id "
757 "with ip - %(ip_addr)s") %773 "with ip - %(ip_addr)s") %
758 ({'name': instance.name,774 ({'name': instance.name,
759 'ip_addr': ip_addr}))775 'ip_addr': ip_v4['ip']}))
760776
761 def _get_datacenter_name_and_ref(self):777 def _get_datacenter_name_and_ref(self):
762 """Get the datacenter name and the reference."""778 """Get the datacenter name and the reference."""
763779
=== 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-05 07:38:25 +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