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. Ensure if port group is properly associated with vlan_interface specified in case of VLAN networking for instances. 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. Removed stale code from vmwareapi stubs. Also updated some comments to be more meaningful. Did pep8 and pylint checks. Tried to improve pylint score for newly added lines of code.
This commit is contained in:
parent
78a63bcad5
commit
6930c62a02
@ -45,8 +45,6 @@ def set_stubs(stubs):
|
||||
stubs.Set(vmware_images, 'get_vmdk_size_and_properties',
|
||||
fake.fake_get_vmdk_size_and_properties)
|
||||
stubs.Set(vmware_images, 'upload_image', fake.fake_upload_image)
|
||||
stubs.Set(vmwareapi_conn.VMWareAPISession, "_get_vim_object",
|
||||
fake_get_vim_object)
|
||||
stubs.Set(vmwareapi_conn.VMWareAPISession, "_get_vim_object",
|
||||
fake_get_vim_object)
|
||||
stubs.Set(vmwareapi_conn.VMWareAPISession, "_is_vim_object",
|
||||
|
@ -409,7 +409,7 @@ def fake_plug_vifs(*args, **kwargs):
|
||||
|
||||
def fake_get_network(*args, **kwargs):
|
||||
"""Fake get network."""
|
||||
return [{'type': 'fake'}]
|
||||
return {'type': 'fake'}
|
||||
|
||||
|
||||
def fake_fetch_image(image, instance, **kwargs):
|
||||
|
@ -17,42 +17,35 @@
|
||||
|
||||
"""VIF drivers for VMWare."""
|
||||
|
||||
from nova import db
|
||||
from nova import exception
|
||||
from nova import flags
|
||||
from nova import log as logging
|
||||
from nova import utils
|
||||
from nova.virt.vif import VIFDriver
|
||||
from nova.virt.vmwareapi_conn import VMWareAPISession
|
||||
from nova.virt.vmwareapi import network_utils
|
||||
|
||||
|
||||
LOG = logging.getLogger("nova.virt.vmwareapi.vif")
|
||||
|
||||
FLAGS = flags.FLAGS
|
||||
FLAGS['vmwareapi_vlan_interface'].SetDefault('vmnic0')
|
||||
|
||||
|
||||
class VMWareVlanBridgeDriver(VIFDriver):
|
||||
"""VIF Driver to setup bridge/VLAN networking using VMWare API."""
|
||||
|
||||
def plug(self, instance, network, mapping):
|
||||
"""Plug the VIF to specified instance using information passed.
|
||||
Currently we are plugging the VIF(s) during instance creation itself.
|
||||
We can use this method when we add support to add additional NIC to
|
||||
an existing instance."""
|
||||
pass
|
||||
|
||||
def ensure_vlan_bridge(self, session, network):
|
||||
"""Create a vlan and bridge unless they already exist."""
|
||||
vlan_num = network['vlan']
|
||||
bridge = network['bridge']
|
||||
bridge_interface = network['bridge_interface']
|
||||
vlan_interface = FLAGS.vmwareapi_vlan_interface
|
||||
|
||||
# Open vmwareapi session
|
||||
host_ip = FLAGS.vmwareapi_host_ip
|
||||
host_username = FLAGS.vmwareapi_host_username
|
||||
host_password = FLAGS.vmwareapi_host_password
|
||||
if not host_ip or host_username is None or host_password is None:
|
||||
raise Exception(_('Must specify vmwareapi_host_ip, '
|
||||
'vmwareapi_host_username '
|
||||
'and vmwareapi_host_password to use '
|
||||
'connection_type=vmwareapi'))
|
||||
session = VMWareAPISession(host_ip, host_username, host_password,
|
||||
FLAGS.vmwareapi_api_retry_count)
|
||||
vlan_interface = bridge_interface
|
||||
# Check if the vlan_interface physical network adapter exists on the
|
||||
# host.
|
||||
if not network_utils.check_if_vlan_interface_exists(session,
|
||||
@ -92,4 +85,6 @@ class VMWareVlanBridgeDriver(VIFDriver):
|
||||
pgroup=pg_vlanid)
|
||||
|
||||
def unplug(self, instance, network, mapping):
|
||||
"""Cleanup operations like deleting port group if no instance
|
||||
is associated with it."""
|
||||
pass
|
||||
|
@ -39,8 +39,7 @@ def split_datastore_path(datastore_path):
|
||||
|
||||
|
||||
def get_vm_create_spec(client_factory, instance, data_store_name,
|
||||
network_name="vmnet0",
|
||||
os_type="otherGuest", network_ref=None):
|
||||
vif_infos, os_type="otherGuest"):
|
||||
"""Builds the VM Create spec."""
|
||||
config_spec = client_factory.create('ns0:VirtualMachineConfigSpec')
|
||||
config_spec.name = instance.name
|
||||
@ -61,14 +60,12 @@ def get_vm_create_spec(client_factory, instance, data_store_name,
|
||||
config_spec.numCPUs = int(instance.vcpus)
|
||||
config_spec.memoryMB = int(instance.memory_mb)
|
||||
|
||||
mac_address = None
|
||||
if instance['mac_addresses']:
|
||||
mac_address = instance['mac_addresses'][0]['address']
|
||||
vif_spec_list = []
|
||||
for vif_info in vif_infos:
|
||||
vif_spec = create_network_spec(client_factory, vif_info)
|
||||
vif_spec_list.append(vif_spec)
|
||||
|
||||
nic_spec = create_network_spec(client_factory,
|
||||
network_name, mac_address)
|
||||
|
||||
device_config_spec = [nic_spec]
|
||||
device_config_spec = vif_spec_list
|
||||
|
||||
config_spec.deviceChange = device_config_spec
|
||||
return config_spec
|
||||
@ -93,8 +90,7 @@ def create_controller_spec(client_factory, key):
|
||||
return virtual_device_config
|
||||
|
||||
|
||||
def create_network_spec(client_factory, network_name, mac_address,
|
||||
network_ref=None):
|
||||
def create_network_spec(client_factory, vif_info):
|
||||
"""
|
||||
Builds a config spec for the addition of a new network
|
||||
adapter to the VM.
|
||||
@ -109,6 +105,9 @@ def create_network_spec(client_factory, network_name, mac_address,
|
||||
# NOTE(asomya): Only works on ESXi if the portgroup binding is set to
|
||||
# ephemeral. Invalid configuration if set to static and the NIC does
|
||||
# not come up on boot if set to dynamic.
|
||||
network_ref = vif_info['network_ref']
|
||||
network_name = vif_info['network_name']
|
||||
mac_address = vif_info['mac_address']
|
||||
backing = None
|
||||
if (network_ref and
|
||||
network_ref['type'] == "DistributedVirtualPortgroup"):
|
||||
@ -295,11 +294,8 @@ def get_dummy_vm_create_spec(client_factory, name, data_store_name):
|
||||
return config_spec
|
||||
|
||||
|
||||
def get_machine_id_change_spec(client_factory, mac, ip_addr, netmask,
|
||||
gateway, broadcast, dns):
|
||||
def get_machine_id_change_spec(client_factory, machine_id_str):
|
||||
"""Builds the machine id change config spec."""
|
||||
machine_id_str = "%s;%s;%s;%s;%s;%s" % (mac, ip_addr, netmask,
|
||||
gateway, broadcast, dns)
|
||||
virtual_machine_config_spec = \
|
||||
client_factory.create('ns0:VirtualMachineConfigSpec')
|
||||
|
||||
|
@ -27,7 +27,6 @@ import urllib2
|
||||
import uuid
|
||||
|
||||
from nova import context as nova_context
|
||||
from nova import db
|
||||
from nova import exception
|
||||
from nova import flags
|
||||
from nova import log as logging
|
||||
@ -111,22 +110,6 @@ class VMWareVMOps(object):
|
||||
client_factory = self._session._get_vim().client.factory
|
||||
service_content = self._session._get_vim().get_service_content()
|
||||
|
||||
network = db.network_get_by_instance(nova_context.get_admin_context(),
|
||||
instance['id'])
|
||||
|
||||
net_name = network['bridge']
|
||||
|
||||
def _check_if_network_bridge_exists():
|
||||
network_ref = \
|
||||
network_utils.get_network_with_the_name(self._session,
|
||||
net_name)
|
||||
if network_ref is None:
|
||||
raise exception.NetworkNotFoundForBridge(bridge=net_name)
|
||||
return network_ref
|
||||
|
||||
self.plug_vifs(instance, network_info)
|
||||
network_obj = _check_if_network_bridge_exists()
|
||||
|
||||
def _get_datastore_ref():
|
||||
"""Get the datastore list and choose the first local storage."""
|
||||
data_stores = self._session._call_method(vim_util, "get_objects",
|
||||
@ -182,11 +165,36 @@ class VMWareVMOps(object):
|
||||
|
||||
vm_folder_mor, res_pool_mor = _get_vmfolder_and_res_pool_mors()
|
||||
|
||||
def _check_if_network_bridge_exists(network_name):
|
||||
network_ref = \
|
||||
network_utils.get_network_with_the_name(self._session,
|
||||
network_name)
|
||||
if network_ref is None:
|
||||
raise exception.NetworkNotFoundForBridge(bridge=network_name)
|
||||
return network_ref
|
||||
|
||||
def _get_vif_infos():
|
||||
vif_infos = []
|
||||
for (network, mapping) in network_info:
|
||||
mac_address = mapping['mac']
|
||||
network_name = network['bridge']
|
||||
if mapping.get('should_create_vlan'):
|
||||
network_ref = self._vif_driver.ensure_vlan_bridge(
|
||||
self._session, network)
|
||||
else:
|
||||
network_ref = _check_if_network_bridge_exists(network_name)
|
||||
vif_infos.append({'network_name': network_name,
|
||||
'mac_address': mac_address,
|
||||
'network_ref': network_ref,
|
||||
})
|
||||
return vif_infos
|
||||
|
||||
vif_infos = _get_vif_infos()
|
||||
|
||||
# Get the create vm config spec
|
||||
config_spec = vm_util.get_vm_create_spec(
|
||||
client_factory, instance,
|
||||
data_store_name, net_name, os_type,
|
||||
network_obj)
|
||||
data_store_name, vif_infos, os_type)
|
||||
|
||||
def _execute_create_vm():
|
||||
"""Create VM on ESX host."""
|
||||
@ -204,8 +212,10 @@ class VMWareVMOps(object):
|
||||
|
||||
_execute_create_vm()
|
||||
|
||||
# Set the machine id for the VM for setting the IP
|
||||
self._set_machine_id(client_factory, instance)
|
||||
# Set the machine.id parameter of the instance to inject
|
||||
# the NIC configuration inside the VM
|
||||
if FLAGS.flat_injected:
|
||||
self._set_machine_id(client_factory, instance, network_info)
|
||||
|
||||
# Naming the VM files in correspondence with the VM instance name
|
||||
# The flat vmdk file name
|
||||
@ -716,39 +726,45 @@ class VMWareVMOps(object):
|
||||
"""Return link to instance's ajax console."""
|
||||
return 'http://fakeajaxconsole/fake_url'
|
||||
|
||||
def _set_machine_id(self, client_factory, instance):
|
||||
def _set_machine_id(self, client_factory, instance, network_info):
|
||||
"""
|
||||
Set the machine id of the VM for guest tools to pick up and change
|
||||
the IP.
|
||||
Set the machine id of the VM for guest tools to pick up and reconfigure
|
||||
the network interfaces.
|
||||
"""
|
||||
admin_context = nova_context.get_admin_context()
|
||||
vm_ref = self._get_vm_ref_from_the_name(instance.name)
|
||||
if vm_ref is None:
|
||||
raise exception.InstanceNotFound(instance_id=instance.id)
|
||||
network = db.network_get_by_instance(nova_context.get_admin_context(),
|
||||
instance['id'])
|
||||
mac_address = None
|
||||
if instance['mac_addresses']:
|
||||
mac_address = instance['mac_addresses'][0]['address']
|
||||
|
||||
net_mask = network["netmask"]
|
||||
gateway = network["gateway"]
|
||||
broadcast = network["broadcast"]
|
||||
machine_id_str = ''
|
||||
for (network, info) in network_info:
|
||||
# TODO(vish): add support for dns2
|
||||
dns = network["dns1"]
|
||||
# TODO(sateesh): add support for injection of ipv6 configuration
|
||||
ip_v4 = ip_v6 = None
|
||||
if 'ips' in info and len(info['ips']) > 0:
|
||||
ip_v4 = info['ips'][0]
|
||||
if 'ip6s' in info and len(info['ip6s']) > 0:
|
||||
ip_v6 = info['ip6s'][0]
|
||||
if len(info['dns']) > 0:
|
||||
dns = info['dns'][0]
|
||||
else:
|
||||
dns = ''
|
||||
|
||||
addresses = db.instance_get_fixed_addresses(admin_context,
|
||||
instance['id'])
|
||||
ip_addr = addresses[0] if addresses else None
|
||||
interface_str = "%s;%s;%s;%s;%s;%s" % \
|
||||
(info['mac'],
|
||||
ip_v4 and ip_v4['ip'] or '',
|
||||
ip_v4 and ip_v4['netmask'] or '',
|
||||
info['gateway'],
|
||||
info['broadcast'],
|
||||
dns)
|
||||
machine_id_str = machine_id_str + interface_str + '#'
|
||||
|
||||
machine_id_change_spec = \
|
||||
vm_util.get_machine_id_change_spec(client_factory, mac_address,
|
||||
ip_addr, net_mask, gateway,
|
||||
broadcast, dns)
|
||||
vm_util.get_machine_id_change_spec(client_factory, machine_id_str)
|
||||
|
||||
LOG.debug(_("Reconfiguring VM instance %(name)s to set the machine id "
|
||||
"with ip - %(ip_addr)s") %
|
||||
({'name': instance.name,
|
||||
'ip_addr': ip_addr}))
|
||||
'ip_addr': ip_v4['ip']}))
|
||||
reconfig_task = self._session._call_method(self._session._get_vim(),
|
||||
"ReconfigVM_Task", vm_ref,
|
||||
spec=machine_id_change_spec)
|
||||
@ -756,7 +772,7 @@ class VMWareVMOps(object):
|
||||
LOG.debug(_("Reconfigured VM instance %(name)s to set the machine id "
|
||||
"with ip - %(ip_addr)s") %
|
||||
({'name': instance.name,
|
||||
'ip_addr': ip_addr}))
|
||||
'ip_addr': ip_v4['ip']}))
|
||||
|
||||
def _get_datacenter_name_and_ref(self):
|
||||
"""Get the datacenter name and the reference."""
|
||||
|
@ -81,16 +81,21 @@ def _bytes2int(bytes):
|
||||
|
||||
def _parse_network_details(machine_id):
|
||||
"""
|
||||
Parse the machine.id field to get MAC, IP, Netmask and Gateway fields
|
||||
machine.id is of the form MAC;IP;Netmask;Gateway;Broadcast;DNS1,DNS2
|
||||
where ';' is the separator.
|
||||
Parse the machine_id to get MAC, IP, Netmask and Gateway fields per NIC.
|
||||
machine_id is of the form ('NIC_record#NIC_record#', '')
|
||||
Each of the NIC will have record NIC_record in the form
|
||||
'MAC;IP;Netmask;Gateway;Broadcast;DNS' where ';' is field separator.
|
||||
Each record is separated by '#' from next record.
|
||||
"""
|
||||
logging.debug(_("Received machine_id from vmtools : %s") % machine_id[0])
|
||||
network_details = []
|
||||
if machine_id[1].strip() == "1":
|
||||
pass
|
||||
else:
|
||||
network_info_list = machine_id[0].split(';')
|
||||
assert len(network_info_list) % 6 == 0
|
||||
for machine_id_str in machine_id[0].split('#'):
|
||||
network_info_list = machine_id_str.split(';')
|
||||
if len(network_info_list) % 6 != 0:
|
||||
break
|
||||
no_grps = len(network_info_list) / 6
|
||||
i = 0
|
||||
while i < no_grps:
|
||||
@ -103,6 +108,7 @@ def _parse_network_details(machine_id):
|
||||
network_info_list[k + 4].strip(),
|
||||
network_info_list[k + 5].strip().split(',')))
|
||||
i += 1
|
||||
logging.debug(_("NIC information from vmtools : %s") % network_details)
|
||||
return network_details
|
||||
|
||||
|
||||
@ -279,6 +285,7 @@ def _filter_duplicates(all_entries):
|
||||
|
||||
|
||||
def _set_rhel_networking(network_details=None):
|
||||
"""Set IPv4 network settings for RHEL distros."""
|
||||
network_details = network_details or []
|
||||
all_dns_servers = []
|
||||
for network_detail in network_details:
|
||||
@ -320,31 +327,33 @@ def _set_rhel_networking(network_details=None):
|
||||
|
||||
|
||||
def _set_ubuntu_networking(network_details=None):
|
||||
"""Set IPv4 network settings for Ubuntu."""
|
||||
network_details = network_details or []
|
||||
""" Set IPv4 network settings for Ubuntu """
|
||||
all_dns_servers = []
|
||||
for network_detail in network_details:
|
||||
interface_file_name = '/etc/network/interfaces'
|
||||
# Remove file
|
||||
os.remove(interface_file_name)
|
||||
# Touch file
|
||||
_execute(['touch', interface_file_name])
|
||||
interface_file = open(interface_file_name, 'w')
|
||||
for device, network_detail in enumerate(network_details):
|
||||
mac_address, ip_address, subnet_mask, gateway, broadcast,\
|
||||
dns_servers = network_detail
|
||||
all_dns_servers.extend(dns_servers)
|
||||
adapter_name, current_ip_address = \
|
||||
_get_linux_adapter_name_and_ip_address(mac_address)
|
||||
|
||||
if adapter_name and not ip_address == current_ip_address:
|
||||
interface_file_name = \
|
||||
'/etc/network/interfaces'
|
||||
# Remove file
|
||||
os.remove(interface_file_name)
|
||||
# Touch file
|
||||
_execute(['touch', interface_file_name])
|
||||
interface_file = open(interface_file_name, 'w')
|
||||
if adapter_name:
|
||||
interface_file.write('\nauto %s' % adapter_name)
|
||||
interface_file.write('\niface %s inet static' % adapter_name)
|
||||
interface_file.write('\nbroadcast %s' % broadcast)
|
||||
interface_file.write('\ngateway %s' % gateway)
|
||||
interface_file.write('\nnetmask %s' % subnet_mask)
|
||||
interface_file.write('\naddress %s' % ip_address)
|
||||
interface_file.write('\naddress %s\n' % ip_address)
|
||||
logging.debug(_("Successfully configured NIC %d with "
|
||||
"NIC info %s") % (device, network_detail))
|
||||
interface_file.close()
|
||||
|
||||
if all_dns_servers:
|
||||
dns_file_name = "/etc/resolv.conf"
|
||||
os.remove(dns_file_name)
|
||||
@ -355,7 +364,8 @@ def _set_ubuntu_networking(network_details=None):
|
||||
for dns_server in unique_entries:
|
||||
dns_file.write("\nnameserver %s" % dns_server)
|
||||
dns_file.close()
|
||||
print "\nRestarting networking....\n"
|
||||
|
||||
logging.debug(_("Restarting networking....\n"))
|
||||
_execute(['/etc/init.d/networking', 'restart'])
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user