¡@

Home 

OpenStack Study: utilsv2.py

OpenStack Index

**** CubicPower OpenStack Study ****

# vim: tabstop=4 shiftwidth=4 softtabstop=4

# Copyright 2013 Cloudbase Solutions SRL

# 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: Alessandro Pilotti, Cloudbase Solutions Srl

# @author: Claudiu Belu, Cloudbase Solutions Srl

from neutron.plugins.hyperv.agent import utils

**** CubicPower OpenStack Study ****

class HyperVUtilsV2(utils.HyperVUtils):

_EXTERNAL_PORT = 'Msvm_ExternalEthernetPort'

_ETHERNET_SWITCH_PORT = 'Msvm_EthernetSwitchPort'

_PORT_ALLOC_SET_DATA = 'Msvm_EthernetPortAllocationSettingData'

_PORT_VLAN_SET_DATA = 'Msvm_EthernetSwitchPortVlanSettingData'

_PORT_SECURITY_SET_DATA = 'Msvm_EthernetSwitchPortSecuritySettingData'

_PORT_ALLOC_ACL_SET_DATA = 'Msvm_EthernetSwitchPortAclSettingData'

_PORT_EXT_ACL_SET_DATA = _PORT_ALLOC_ACL_SET_DATA

_LAN_ENDPOINT = 'Msvm_LANEndpoint'

_STATE_DISABLED = 3

_OPERATION_MODE_ACCESS = 1

_VIRTUAL_SYSTEM_SETTING_DATA = 'Msvm_VirtualSystemSettingData'

_VM_SUMMARY_ENABLED_STATE = 100

_HYPERV_VM_STATE_ENABLED = 2

_ACL_DIR_IN = 1

_ACL_DIR_OUT = 2

_ACL_TYPE_IPV4 = 2

_ACL_TYPE_IPV6 = 3

_ACL_ACTION_ALLOW = 1

_ACL_ACTION_DENY = 2

_ACL_ACTION_METER = 3

_METRIC_ENABLED = 2

_NET_IN_METRIC_NAME = 'Filtered Incoming Network Traffic'

_NET_OUT_METRIC_NAME = 'Filtered Outgoing Network Traffic'

_ACL_APPLICABILITY_LOCAL = 1

_ACL_APPLICABILITY_REMOTE = 2

_ACL_DEFAULT = 'ANY'

_IPV4_ANY = '0.0.0.0/0'

_IPV6_ANY = '::/0'

_TCP_PROTOCOL = 'tcp'

_UDP_PROTOCOL = 'udp'

_MAX_WEIGHT = 65500

_wmi_namespace = '//./root/virtualization/v2'

**** CubicPower OpenStack Study ****

    def __init__(self):

        super(HyperVUtilsV2, self).__init__()

**** CubicPower OpenStack Study ****

    def connect_vnic_to_vswitch(self, vswitch_name, switch_port_name):

        vnic = self._get_vnic_settings(switch_port_name)

        vswitch = self._get_vswitch(vswitch_name)

        port, found = self._get_switch_port_allocation(switch_port_name, True)

        port.HostResource = [vswitch.path_()]

        port.Parent = vnic.path_()

        if not found:

            vm = self._get_vm_from_res_setting_data(vnic)

            self._add_virt_resource(vm, port)

        else:

            self._modify_virt_resource(port)

**** CubicPower OpenStack Study ****

    def _modify_virt_resource(self, res_setting_data):

        vs_man_svc = self._conn.Msvm_VirtualSystemManagementService()[0]

        (job_path, out_set_data, ret_val) = vs_man_svc.ModifyResourceSettings(

            ResourceSettings=[res_setting_data.GetText_(1)])

        self._check_job_status(ret_val, job_path)

**** CubicPower OpenStack Study ****

    def _add_virt_resource(self, vm, res_setting_data):

        vs_man_svc = self._conn.Msvm_VirtualSystemManagementService()[0]

        (job_path, out_set_data, ret_val) = vs_man_svc.AddResourceSettings(

            vm.path_(), [res_setting_data.GetText_(1)])

        self._check_job_status(ret_val, job_path)

**** CubicPower OpenStack Study ****

    def _remove_virt_resource(self, res_setting_data):

        vs_man_svc = self._conn.Msvm_VirtualSystemManagementService()[0]

        (job, ret_val) = vs_man_svc.RemoveResourceSettings(

            ResourceSettings=[res_setting_data.path_()])

        self._check_job_status(ret_val, job)

**** CubicPower OpenStack Study ****

    def _add_virt_feature(self, element, res_setting_data):

        vs_man_svc = self._conn.Msvm_VirtualSystemManagementService()[0]

        (job_path, out_set_data, ret_val) = vs_man_svc.AddFeatureSettings(

            element.path_(), [res_setting_data.GetText_(1)])

        self._check_job_status(ret_val, job_path)

**** CubicPower OpenStack Study ****

    def _remove_virt_feature(self, feature_resource):

        vs_man_svc = self._conn.Msvm_VirtualSystemManagementService()[0]

        (job_path, ret_val) = vs_man_svc.RemoveFeatureSettings(

            FeatureSettings=[feature_resource.path_()])

        self._check_job_status(ret_val, job_path)

**** CubicPower OpenStack Study ****

    def disconnect_switch_port(

            self, vswitch_name, switch_port_name, delete_port):

        """Disconnects the switch port."""

        sw_port, found = self._get_switch_port_allocation(switch_port_name)

        if not sw_port:

            # Port not found. It happens when the VM was already deleted.

            return

        if delete_port:

            self._remove_virt_resource(sw_port)

        else:

            sw_port.EnabledState = self._STATE_DISABLED

            self._modify_virt_resource(sw_port)

**** CubicPower OpenStack Study ****

    def _get_vswitch(self, vswitch_name):

        vswitch = self._conn.Msvm_VirtualEthernetSwitch(

            ElementName=vswitch_name)

        if not len(vswitch):

            raise utils.HyperVException(msg=_('VSwitch not found: %s') %

                                        vswitch_name)

        return vswitch[0]

**** CubicPower OpenStack Study ****

    def _get_vswitch_external_port(self, vswitch):

        vswitch_ports = vswitch.associators(

            wmi_result_class=self._ETHERNET_SWITCH_PORT)

        for vswitch_port in vswitch_ports:

            lan_endpoints = vswitch_port.associators(

                wmi_result_class=self._LAN_ENDPOINT)

            if len(lan_endpoints):

                lan_endpoints = lan_endpoints[0].associators(

                    wmi_result_class=self._LAN_ENDPOINT)

                if len(lan_endpoints):

                    ext_port = lan_endpoints[0].associators(

                        wmi_result_class=self._EXTERNAL_PORT)

                    if ext_port:

                        return vswitch_port

**** CubicPower OpenStack Study ****

    def set_vswitch_port_vlan_id(self, vlan_id, switch_port_name):

        port_alloc, found = self._get_switch_port_allocation(switch_port_name)

        if not found:

            raise utils.HyperVException(

                msg=_('Port Allocation not found: %s') % switch_port_name)

        vs_man_svc = self._conn.Msvm_VirtualSystemManagementService()[0]

        vlan_settings = self._get_vlan_setting_data_from_port_alloc(port_alloc)

        if vlan_settings:

            # Removing the feature because it cannot be modified

            # due to a wmi exception.

            (job_path, ret_val) = vs_man_svc.RemoveFeatureSettings(

                FeatureSettings=[vlan_settings.path_()])

            self._check_job_status(ret_val, job_path)

        (vlan_settings, found) = self._get_vlan_setting_data(switch_port_name)

        vlan_settings.AccessVlanId = vlan_id

        vlan_settings.OperationMode = self._OPERATION_MODE_ACCESS

        (job_path, out, ret_val) = vs_man_svc.AddFeatureSettings(

            port_alloc.path_(), [vlan_settings.GetText_(1)])

        self._check_job_status(ret_val, job_path)

**** CubicPower OpenStack Study ****

    def _get_vlan_setting_data_from_port_alloc(self, port_alloc):

        return self._get_first_item(port_alloc.associators(

            wmi_result_class=self._PORT_VLAN_SET_DATA))

**** CubicPower OpenStack Study ****

    def _get_vlan_setting_data(self, switch_port_name, create=True):

        return self._get_setting_data(

            self._PORT_VLAN_SET_DATA,

            switch_port_name, create)

**** CubicPower OpenStack Study ****

    def _get_switch_port_allocation(self, switch_port_name, create=False):

        return self._get_setting_data(

            self._PORT_ALLOC_SET_DATA,

            switch_port_name, create)

**** CubicPower OpenStack Study ****

    def _get_setting_data(self, class_name, element_name, create=True):

        element_name = element_name.replace("'", '"')

        q = self._conn.query("SELECT * FROM %(class_name)s WHERE "

                             "ElementName = '%(element_name)s'" %

                             {"class_name": class_name,

                              "element_name": element_name})

        data = self._get_first_item(q)

        found = data is not None

        if not data and create:

            data = self._get_default_setting_data(class_name)

            data.ElementName = element_name

        return data, found

**** CubicPower OpenStack Study ****

    def _get_default_setting_data(self, class_name):

        return self._conn.query("SELECT * FROM %s WHERE InstanceID "

                                "LIKE '%%\\Default'" % class_name)[0]

**** CubicPower OpenStack Study ****

    def _get_first_item(self, obj):

        if obj:

            return obj[0]

**** CubicPower OpenStack Study ****

    def enable_port_metrics_collection(self, switch_port_name):

        port, found = self._get_switch_port_allocation(switch_port_name, False)

        if not found:

            return

        # Add the ACLs only if they don't already exist

        acls = port.associators(wmi_result_class=self._PORT_ALLOC_ACL_SET_DATA)

        for acl_type in [self._ACL_TYPE_IPV4, self._ACL_TYPE_IPV6]:

            for acl_dir in [self._ACL_DIR_IN, self._ACL_DIR_OUT]:

                _acls = self._filter_acls(

                    acls, self._ACL_ACTION_METER, acl_dir, acl_type)

                if not _acls:

                    acl = self._create_acl(

                        acl_dir, acl_type, self._ACL_ACTION_METER)

                    self._add_virt_feature(port, acl)

**** CubicPower OpenStack Study ****

    def enable_control_metrics(self, switch_port_name):

        port, found = self._get_switch_port_allocation(switch_port_name, False)

        if not found:

            return

        metric_svc = self._conn.Msvm_MetricService()[0]

        metric_names = [self._NET_IN_METRIC_NAME, self._NET_OUT_METRIC_NAME]

        for metric_name in metric_names:

            metric_def = self._conn.CIM_BaseMetricDefinition(Name=metric_name)

            if metric_def:

                metric_svc.ControlMetrics(

                    Subject=port.path_(),

                    Definition=metric_def[0].path_(),

                    MetricCollectionEnabled=self._METRIC_ENABLED)

**** CubicPower OpenStack Study ****

    def can_enable_control_metrics(self, switch_port_name):

        port, found = self._get_switch_port_allocation(switch_port_name, False)

        if not found:

            return False

        if not self._is_port_vm_started(port):

            return False

        # all 4 meter ACLs must be existent first. (2 x direction)

        acls = port.associators(wmi_result_class=self._PORT_ALLOC_ACL_SET_DATA)

        acls = [a for a in acls if a.Action == self._ACL_ACTION_METER]

        if len(acls) < 2:

            return False

        return True

**** CubicPower OpenStack Study ****

    def _is_port_vm_started(self, port):

        vs_man_svc = self._conn.Msvm_VirtualSystemManagementService()[0]

        vmsettings = port.associators(

            wmi_result_class=self._VIRTUAL_SYSTEM_SETTING_DATA)

        #See http://msdn.microsoft.com/en-us/library/cc160706%28VS.85%29.aspx

        (ret_val, summary_info) = vs_man_svc.GetSummaryInformation(

            [self._VM_SUMMARY_ENABLED_STATE],

            [v.path_() for v in vmsettings])

        if ret_val or not summary_info:

            raise utils.HyperVException(msg=_('Cannot get VM summary data '

                                              'for: %s') % port.ElementName)

        return summary_info[0].EnabledState is self._HYPERV_VM_STATE_ENABLED

**** CubicPower OpenStack Study ****

    def create_security_rule(self, switch_port_name, direction, acl_type,

                             local_port, protocol, remote_address):

        port, found = self._get_switch_port_allocation(switch_port_name, False)

        if not found:

            return

        # Add the ACLs only if they don't already exist

        acls = port.associators(wmi_result_class=self._PORT_EXT_ACL_SET_DATA)

        weight = self._get_new_weight(acls)

        self._bind_security_rule(

            port, direction, acl_type, self._ACL_ACTION_ALLOW, local_port,

            protocol, remote_address, weight)

**** CubicPower OpenStack Study ****

    def remove_security_rule(self, switch_port_name, direction, acl_type,

                             local_port, protocol, remote_address):

        port, found = self._get_switch_port_allocation(switch_port_name, False)

        if not found:

            # Port not found. It happens when the VM was already deleted.

            return

        acls = port.associators(wmi_result_class=self._PORT_EXT_ACL_SET_DATA)

        filtered_acls = self._filter_security_acls(

            acls, self._ACL_ACTION_ALLOW, direction, acl_type, local_port,

            protocol, remote_address)

        for acl in filtered_acls:

            self._remove_virt_feature(acl)

**** CubicPower OpenStack Study ****

    def create_default_reject_all_rules(self, switch_port_name):

        port, found = self._get_switch_port_allocation(switch_port_name, False)

        if not found:

            raise utils.HyperVException(

                msg=_('Port Allocation not found: %s') % switch_port_name)

        acls = port.associators(wmi_result_class=self._PORT_EXT_ACL_SET_DATA)

        filtered_acls = [v for v in acls if v.Action == self._ACL_ACTION_DENY]

        # 2 directions x 2 address types x 2 protocols = 8 ACLs

        if len(filtered_acls) >= 8:

            return

        for acl in filtered_acls:

            self._remove_virt_feature(acl)

        weight = 0

        ipv4_pair = (self._ACL_TYPE_IPV4, self._IPV4_ANY)

        ipv6_pair = (self._ACL_TYPE_IPV6, self._IPV6_ANY)

        for direction in [self._ACL_DIR_IN, self._ACL_DIR_OUT]:

            for acl_type, address in [ipv4_pair, ipv6_pair]:

                for protocol in [self._TCP_PROTOCOL, self._UDP_PROTOCOL]:

                    self._bind_security_rule(

                        port, direction, acl_type, self._ACL_ACTION_DENY,

                        self._ACL_DEFAULT, protocol, address, weight)

                    weight += 1

**** CubicPower OpenStack Study ****

    def _bind_security_rule(self, port, direction, acl_type, action,

                            local_port, protocol, remote_address, weight):

        acls = port.associators(wmi_result_class=self._PORT_EXT_ACL_SET_DATA)

        filtered_acls = self._filter_security_acls(

            acls, action, direction, acl_type, local_port, protocol,

            remote_address)

        for acl in filtered_acls:

            self._remove_virt_feature(acl)

        acl = self._create_security_acl(

            direction, acl_type, action, local_port, protocol, remote_address,

            weight)

        self._add_virt_feature(port, acl)

**** CubicPower OpenStack Study ****

    def _create_acl(self, direction, acl_type, action):

        acl = self._get_default_setting_data(self._PORT_ALLOC_ACL_SET_DATA)

        acl.set(Direction=direction,

                AclType=acl_type,

                Action=action,

                Applicability=self._ACL_APPLICABILITY_LOCAL)

        return acl

**** CubicPower OpenStack Study ****

    def _create_security_acl(self, direction, acl_type, action, local_port,

                             protocol, remote_ip_address, weight):

        acl = self._create_acl(direction, acl_type, action)

        (remote_address, remote_prefix_length) = remote_ip_address.split('/')

        acl.set(Applicability=self._ACL_APPLICABILITY_REMOTE,

                RemoteAddress=remote_address,

                RemoteAddressPrefixLength=remote_prefix_length)

        return acl

**** CubicPower OpenStack Study ****

    def _filter_acls(self, acls, action, direction, acl_type, remote_addr=""):

        return [v for v in acls

                if v.Action == action and

                v.Direction == direction and

                v.AclType == acl_type and

                v.RemoteAddress == remote_addr]

**** CubicPower OpenStack Study ****

    def _filter_security_acls(self, acls, acl_action, direction, acl_type,

                              local_port, protocol, remote_addr=""):

        (remote_address, remote_prefix_length) = remote_addr.split('/')

        remote_prefix_length = int(remote_prefix_length)

        return [v for v in acls

                if v.Direction == direction and

                v.Action in [self._ACL_ACTION_ALLOW, self._ACL_ACTION_DENY] and

                v.AclType == acl_type and

                v.RemoteAddress == remote_address and

                v.RemoteAddressPrefixLength == remote_prefix_length]

**** CubicPower OpenStack Study ****

    def _get_new_weight(self, acls):

        return 0

**** CubicPower OpenStack Study ****

class HyperVUtilsV2R2(HyperVUtilsV2):

_PORT_EXT_ACL_SET_DATA = 'Msvm_EthernetSwitchPortExtendedAclSettingData'

_MAX_WEIGHT = 65500

**** CubicPower OpenStack Study ****

    def create_security_rule(self, switch_port_name, direction, acl_type,

                             local_port, protocol, remote_address):

        protocols = [protocol]

        if protocol is self._ACL_DEFAULT:

            protocols = [self._TCP_PROTOCOL, self._UDP_PROTOCOL]

        for proto in protocols:

            super(HyperVUtilsV2R2, self).create_security_rule(

                switch_port_name, direction, acl_type, local_port,

                proto, remote_address)

**** CubicPower OpenStack Study ****

    def remove_security_rule(self, switch_port_name, direction, acl_type,

                             local_port, protocol, remote_address):

        protocols = [protocol]

        if protocol is self._ACL_DEFAULT:

            protocols = ['tcp', 'udp']

        for proto in protocols:

            super(HyperVUtilsV2R2, self).remove_security_rule(

                switch_port_name, direction, acl_type,

                local_port, proto, remote_address)

**** CubicPower OpenStack Study ****

    def _create_security_acl(self, direction, acl_type, action, local_port,

                             protocol, remote_addr, weight):

        acl = self._get_default_setting_data(self._PORT_EXT_ACL_SET_DATA)

        acl.set(Direction=direction,

                Action=action,

                LocalPort=str(local_port),

                Protocol=protocol,

                RemoteIPAddress=remote_addr,

                IdleSessionTimeout=0,

                Weight=weight)

        return acl

**** CubicPower OpenStack Study ****

    def _filter_security_acls(self, acls, action, direction, acl_type,

                              local_port, protocol, remote_addr=""):

        return [v for v in acls

                if v.Action == action and

                v.Direction == direction and

                v.LocalPort == str(local_port) and

                v.Protocol == protocol and

                v.RemoteIPAddress == remote_addr]

**** CubicPower OpenStack Study ****

    def _get_new_weight(self, acls):

        acls = [a for a in acls if a.Action is not self._ACL_ACTION_DENY]

        if not acls:

            return self._MAX_WEIGHT - 1

        weights = [a.Weight for a in acls]

        min_weight = min(weights)

        for weight in range(min_weight, self._MAX_WEIGHT):

            if weight not in weights:

                return weight

        return min_weight - 1