vmware-nsx/quantum/plugins/hyperv/agent/utils.py
Mark McLoughlin b5990a7bd7 Use oslo-config-2013.1b3
The cfg API is now available via the oslo-config library, so switch to
it and remove the copied-and-pasted version.

Add the 2013.1b3 tarball to tools/pip-requires - this will be changed
to 'oslo-config>=2013.1' when oslo-config is published to pypi. This
will happen in time for grizzly final.

Remove the 'deps = pep8' from tox.ini as it means all the other deps
get installed with easy_install which can't install oslo-config from
the URL.

Retain dummy cfg.py file until keystoneclient middleware has been
updated (I18c450174277c8e2d15ed93879da6cd92074c27a).

Change-Id: I4815aeb8a9341a31a250e920157f15ee15cfc5bc
2013-02-17 17:33:05 +00:00

284 lines
11 KiB
Python

# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2013 Cloudbase Solutions SRL
# Copyright 2013 Pedro Navarro Perez
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
# @author: Pedro Navarro Perez
# @author: Alessandro Pilotti, Cloudbase Solutions Srl
import sys
import time
from oslo.config import cfg
from quantum.common import exceptions as q_exc
from quantum.openstack.common import log as logging
# Check needed for unit testing on Unix
if sys.platform == 'win32':
import wmi
CONF = cfg.CONF
LOG = logging.getLogger(__name__)
class HyperVException(q_exc.QuantumException):
message = _('HyperVException: %(msg)s')
SET_ACCESS_MODE = 0
VLAN_ID_ADD = 1
VLAN_ID_REMOVE = 2
ENDPOINT_MODE_ACCESS = 2
ENDPOINT_MODE_TRUNK = 5
WMI_JOB_STATE_RUNNING = 4
WMI_JOB_STATE_COMPLETED = 7
class HyperVUtils(object):
def __init__(self):
self._wmi_conn = None
@property
def _conn(self):
if self._wmi_conn is None:
self._wmi_conn = wmi.WMI(moniker='//./root/virtualization')
return self._wmi_conn
def get_switch_ports(self, vswitch_name):
vswitch = self._get_vswitch(vswitch_name)
vswitch_ports = vswitch.associators(
wmi_result_class='Msvm_SwitchPort')
return set(p.Name for p in vswitch_ports)
def vnic_port_exists(self, port_id):
try:
self._get_vnic_settings(port_id)
except Exception:
return False
return True
def get_vnic_ids(self):
return set(
p.ElementName
for p in self._conn.Msvm_SyntheticEthernetPortSettingData())
def _get_vnic_settings(self, vnic_name):
vnic_settings = self._conn.Msvm_SyntheticEthernetPortSettingData(
ElementName=vnic_name)
if not len(vnic_settings):
raise HyperVException(msg=_('Vnic not found: %s') % vnic_name)
return vnic_settings[0]
def connect_vnic_to_vswitch(self, vswitch_name, switch_port_name):
vnic_settings = self._get_vnic_settings(switch_port_name)
if not vnic_settings.Connection or not vnic_settings.Connection[0]:
port = self.get_port_by_id(switch_port_name, vswitch_name)
if port:
port_path = port.Path_()
else:
port_path = self._create_switch_port(
vswitch_name, switch_port_name)
vnic_settings.Connection = [port_path]
self._modify_virt_resource(vnic_settings)
def _get_vm_from_res_setting_data(self, res_setting_data):
sd = res_setting_data.associators(
wmi_result_class='Msvm_VirtualSystemSettingData')
vm = sd[0].associators(
wmi_result_class='Msvm_ComputerSystem')
return vm[0]
def _modify_virt_resource(self, res_setting_data):
vm = self._get_vm_from_res_setting_data(res_setting_data)
vs_man_svc = self._conn.Msvm_VirtualSystemManagementService()[0]
(job_path,
ret_val) = vs_man_svc.ModifyVirtualSystemResources(
vm.Path_(), [res_setting_data.GetText_(1)])
self._check_job_status(ret_val, job_path)
def _check_job_status(self, ret_val, jobpath):
"""Poll WMI job state for completion"""
if not ret_val:
return
elif ret_val != WMI_JOB_STATE_RUNNING:
raise HyperVException(msg=_('Job failed with error %d' % ret_val))
job_wmi_path = jobpath.replace('\\', '/')
job = wmi.WMI(moniker=job_wmi_path)
while job.JobState == WMI_JOB_STATE_RUNNING:
time.sleep(0.1)
job = wmi.WMI(moniker=job_wmi_path)
if job.JobState != WMI_JOB_STATE_COMPLETED:
job_state = job.JobState
if job.path().Class == "Msvm_ConcreteJob":
err_sum_desc = job.ErrorSummaryDescription
err_desc = job.ErrorDescription
err_code = job.ErrorCode
raise HyperVException(
msg=_("WMI job failed with status %(job_state)d. "
"Error details: %(err_sum_desc)s - %(err_desc)s - "
"Error code: %(err_code)d") % locals())
else:
(error, ret_val) = job.GetError()
if not ret_val and error:
raise HyperVException(
msg=_("WMI job failed with status %(job_state)d. "
"Error details: %(error)s") % locals())
else:
raise HyperVException(
msg=_("WMI job failed with status %(job_state)d. "
"No error description available") % locals())
desc = job.Description
elap = job.ElapsedTime
LOG.debug(_("WMI job succeeded: %(desc)s, Elapsed=%(elap)s") %
locals())
def _create_switch_port(self, vswitch_name, switch_port_name):
""" Creates a switch port """
switch_svc = self._conn.Msvm_VirtualSwitchManagementService()[0]
vswitch_path = self._get_vswitch(vswitch_name).path_()
(new_port, ret_val) = switch_svc.CreateSwitchPort(
Name=switch_port_name,
FriendlyName=switch_port_name,
ScopeOfResidence="",
VirtualSwitch=vswitch_path)
if ret_val != 0:
raise HyperVException(
msg=_('Failed creating port for %s') % vswitch_name)
return new_port
def disconnect_switch_port(
self, vswitch_name, switch_port_name, delete_port):
""" Disconnects the switch port """
switch_svc = self._conn.Msvm_VirtualSwitchManagementService()[0]
switch_port_path = self._get_switch_port_path_by_name(
switch_port_name)
if not switch_port_path:
# Port not found. It happens when the VM was already deleted.
return
(ret_val, ) = switch_svc.DisconnectSwitchPort(
SwitchPort=switch_port_path)
if ret_val != 0:
raise HyperVException(
msg=_('Failed to disconnect port %(switch_port_name)s '
'from switch %(vswitch_name)s '
'with error %(ret_val)s') % locals())
if delete_port:
(ret_val, ) = switch_svc.DeleteSwitchPort(
SwitchPort=switch_port_path)
if ret_val != 0:
raise HyperVException(
msg=_('Failed to delete port %(switch_port_name)s '
'from switch %(vswitch_name)s '
'with error %(ret_val)s') % locals())
def _get_vswitch(self, vswitch_name):
vswitch = self._conn.Msvm_VirtualSwitch(ElementName=vswitch_name)
if not len(vswitch):
raise HyperVException(msg=_('VSwitch not found: %s') %
vswitch_name)
return vswitch[0]
def _get_vswitch_external_port(self, vswitch):
vswitch_ports = vswitch.associators(
wmi_result_class='Msvm_SwitchPort')
for vswitch_port in vswitch_ports:
lan_endpoints = vswitch_port.associators(
wmi_result_class='Msvm_SwitchLanEndpoint')
if len(lan_endpoints):
ext_port = lan_endpoints[0].associators(
wmi_result_class='Msvm_ExternalEthernetPort')
if ext_port:
return vswitch_port
def _set_vswitch_external_port_vlan_id(self, vswitch_name, action,
vlan_id=None):
vswitch = self._get_vswitch(vswitch_name)
ext_port = self._get_vswitch_external_port(vswitch)
if not ext_port:
return
vlan_endpoint = ext_port.associators(
wmi_association_class='Msvm_BindsTo')[0]
vlan_endpoint_settings = vlan_endpoint.associators(
wmi_association_class='Msvm_NetworkElementSettingData')[0]
mode = ENDPOINT_MODE_TRUNK
trunked_vlans = vlan_endpoint_settings.TrunkedVLANList
new_trunked_vlans = trunked_vlans
if action == VLAN_ID_ADD:
if vlan_id not in trunked_vlans:
new_trunked_vlans += (vlan_id,)
elif action == VLAN_ID_REMOVE:
if vlan_id in trunked_vlans:
new_trunked_vlans = [
v for v in trunked_vlans if v != vlan_id
]
elif action == SET_ACCESS_MODE:
mode = ENDPOINT_MODE_ACCESS
new_trunked_vlans = ()
if vlan_endpoint.DesiredEndpointMode != mode:
vlan_endpoint.DesiredEndpointMode = mode
vlan_endpoint.put()
if len(trunked_vlans) != len(new_trunked_vlans):
vlan_endpoint_settings.TrunkedVLANList = new_trunked_vlans
vlan_endpoint_settings.put()
def set_vswitch_port_vlan_id(self, vlan_id, switch_port_name):
vlan_endpoint_settings = self._conn.Msvm_VLANEndpointSettingData(
ElementName=switch_port_name)[0]
if vlan_endpoint_settings.AccessVLAN != vlan_id:
vlan_endpoint_settings.AccessVLAN = vlan_id
vlan_endpoint_settings.put()
def set_vswitch_mode_access(self, vswitch_name):
LOG.info(_('Setting vswitch %s in access mode (flat)'), vswitch_name)
self._set_vswitch_external_port_vlan_id(vswitch_name, SET_ACCESS_MODE)
def add_vlan_id_to_vswitch(self, vlan_id, vswitch_name):
LOG.info(_('Adding VLAN %s to vswitch %s'),
vlan_id, vswitch_name)
self._set_vswitch_external_port_vlan_id(vswitch_name, VLAN_ID_ADD,
vlan_id)
def remove_vlan_id_from_vswitch(self, vlan_id, vswitch_name):
LOG.info(_('Removing VLAN %s from vswitch %s'),
vlan_id, vswitch_name)
self._set_vswitch_external_port_vlan_id(vswitch_name, VLAN_ID_REMOVE,
vlan_id)
def _get_switch_port_path_by_name(self, switch_port_name):
vswitch = self._conn.Msvm_SwitchPort(ElementName=switch_port_name)
if vswitch:
return vswitch[0].path_()
def get_vswitch_id(self, vswitch_name):
vswitch = self._get_vswitch(vswitch_name)
return vswitch.Name
def get_port_by_id(self, port_id, vswitch_name):
vswitch = self._get_vswitch(vswitch_name)
switch_ports = vswitch.associators(wmi_result_class='Msvm_SwitchPort')
for switch_port in switch_ports:
if (switch_port.ElementName == port_id):
return switch_port