Пример #1
0
 def test_get_switch_device_match(self):
     self.assertEqual(
         device_utils.get_switch_device(self.devices, switch_info='A'),
         self.devices['A'])
     self.assertEqual(
         device_utils.get_switch_device(
             self.devices, ngs_mac_address='aa:bb:cc:dd:ee:ff'),
         self.devices['B'])
Пример #2
0
 def test_get_switch_device_fallback_to_switch_info(self):
     self.assertEqual(
         self.devices['A'],
         device_utils.get_switch_device(
             self.devices,
             switch_info='A',
             ngs_mac_address='11:22:33:44:55:77'))
Пример #3
0
    def _unplug_port_from_network(self, port, network):
        """Unplug a port from a network.

        If the configuration required to unplug the port is not present
        (e.g. local link information), the port will not be unplugged and no
        exception will be raised.

        :param port: The port to unplug
        :param network: The network from which to unplug the port
        """
        binding_profile = port['binding:profile']
        local_link_information = binding_profile.get('local_link_information')
        local_group_information = binding_profile.get(
            'local_group_information')
        if not local_link_information:
            return
        if local_group_information:
            self._lag_alter_local_link(local_group_information,
                                       local_link_information)
        for switch in local_link_information:
            switch_info = switch.get('switch_info')
            switch_id = switch.get('switch_id')
            switch_device = device_utils.get_switch_device(
                self.switches,
                switch_info=switch_info,
                ngs_mac_address=switch_id)
            if not switch_device:
                return
            port_id = local_link_information[0].get('port_id')
            # If segmentation ID is None, set vlan 1
            segmentation_id = network.get('provider:segmentation_id') or '1'
            LOG.debug("Unplugging port {port} on {switch_info} from vlan: "
                      "{segmentation_id}".format(
                          port=port_id,
                          switch_info=switch_info,
                          segmentation_id=segmentation_id))
            try:
                if self._is_trunk(
                        port) and switch_device.get_trunk_mode() == "dynamic":
                    switch_device.unset_trunk(port_id, segmentation_id)
                else:
                    switch_device.delete_port(port_id, segmentation_id)
            except Exception as e:
                LOG.error(
                    "Failed to unplug port %(port_id)s "
                    "on device: %(switch)s from network %(net_id)s "
                    "reason: %(exc)s", {
                        'port_id': port['id'],
                        'net_id': network['id'],
                        'switch': switch_info,
                        'exc': e
                    })
                raise e
        LOG.info(
            'Port %(port_id)s has been unplugged from network '
            '%(net_id)s on device %(device)s', {
                'port_id': port['id'],
                'net_id': network['id'],
                'device': switch_info
            })
Пример #4
0
    def _bind_port_to_switch(self, context, port, switch):
        switch_info = switch.get('switch_info')
        switch_id = switch.get('switch_id')
        switch_device = device_utils.get_switch_device(
            self.switches, switch_info=switch_info, ngs_mac_address=switch_id)
        if not switch:
            return
        network = context.network.current

        net_type = network['provider:network_type']
        if net_type != 'vlan':
            raise Exception(
                "Provider network type was {} but shoule be 'vlan'".format(
                    net_type))

        physnet = network['provider:physical_network']
        switch_physnets = switch_device._get_physical_networks()
        if switch_physnets and physnet not in switch_physnets:
            LOG.error(
                "Cannot bind port %(port)s as device %(device)s is "
                "not on physical network %(physnet)", {
                    'port_id': port['id'],
                    'device': switch_info,
                    'physnet': physnet
                })
            return
        port_id = switch.get('port_id')
        segments = context.segments_to_bind
        # If segmentation ID is None, set vlan 1
        segmentation_id = segments[0].get('segmentation_id') or '1'
        provisioning_blocks.add_provisioning_component(context._plugin_context,
                                                       port['id'],
                                                       resources.PORT,
                                                       GENERIC_SWITCH_ENTITY)
        LOG.debug("Putting port {port} on {switch_info} to vlan: "
                  "{segmentation_id}".format(port=port_id,
                                             switch_info=switch_info,
                                             segmentation_id=segmentation_id))

        if self._is_trunk(
                port) and switch_device.get_trunk_mode() == 'dynamic':
            trunk_details = port['trunk_details']
            self._setup_trunk(switch_device, network, trunk_details, port_id)
        else:
            # Move port to network
            switch_device.plug_port_to_network(port_id, segmentation_id)
            LOG.info(
                "Successfully bound port %(port_id)s in segment "
                "%(segment_id)s on device %(device)s", {
                    'port_id': port['id'],
                    'device': switch_info,
                    'segment_id': segmentation_id
                })

        context.set_binding(segments[0][api.ID], portbindings.VIF_TYPE_OTHER,
                            {})
Пример #5
0
    def _unplug_port_from_network(self, port, network):
        """Unplug a port from a network.

        If the configuration required to unplug the port is not present
        (e.g. local link information), the port will not be unplugged and no
        exception will be raised.

        :param port: The port to unplug
        :param network: The network from which to unplug the port
        """
        binding_profile = port['binding:profile']
        local_link_information = binding_profile.get('local_link_information')
        if not local_link_information:
            return
        switch_info = local_link_information[0].get('switch_info')
        switch_id = local_link_information[0].get('switch_id')
        switch = device_utils.get_switch_device(self.switches,
                                                switch_info=switch_info,
                                                ngs_mac_address=switch_id)
        if not switch:
            return
        port_id = local_link_information[0].get('port_id')
        segmentation_id = network.get('provider:segmentation_id', '1')
        LOG.debug("Unplugging port {port} on {switch_info} from vlan: "
                  "{segmentation_id}".format(port=port_id,
                                             switch_info=switch_info,
                                             segmentation_id=segmentation_id))
        try:
            if hasattr(devices, 'corsa_devices') and isinstance(
                    switch, devices.corsa_devices.corsa2100.CorsaDP2100):
                switch.delete_port(port_id,
                                   segmentation_id,
                                   vfc_host=self.vfcHost)
            else:
                switch.delete_port(port_id, segmentation_id)

        except Exception as e:
            LOG.error(
                "Failed to unplug port %(port_id)s "
                "on device: %(switch)s from network %(net_id)s "
                "reason: %(exc)s", {
                    'port_id': port['id'],
                    'net_id': network['id'],
                    'switch': switch_info,
                    'exc': e
                })
            raise e
        LOG.info(
            'Port %(port_id)s has been unplugged from network '
            ' %(net_id)s on device %(device)s', {
                'port_id': port['id'],
                'net_id': network['id'],
                'device': switch_info
            })
    def _unplug_port_from_network(self, port, network):
        """Unplug a port from a network.

        If the configuration required to unplug the port is not present
        (e.g. local link information), the port will not be unplugged and no
        exception will be raised.

        :param port: The port to unplug
        :param network: The network from which to unplug the port
        """
        binding_profile = port['binding:profile']
        local_link_information = binding_profile.get('local_link_information')
        if not local_link_information:
            return
        switch_info = local_link_information[0].get('switch_info')
        switch_id = local_link_information[0].get('switch_id')
        switch = device_utils.get_switch_device(self.switches,
                                                switch_info=switch_info,
                                                ngs_mac_address=switch_id)
        if not switch:
            return
        port_id = local_link_information[0].get('port_id')
        # If segmentation ID is None, set vlan 1
        segmentation_id = network.get('provider:segmentation_id') or 1
        LOG.debug(
            "Unplugging port %(port)s on %(switch_info)s from vlan: "
            "%(segmentation_id)s", {
                'port': port_id,
                'switch_info': switch_info,
                'segmentation_id': segmentation_id
            })
        try:
            switch.delete_port(port_id, segmentation_id)
        except Exception as e:
            LOG.error(
                "Failed to unplug port %(port_id)s "
                "on device: %(switch)s from network %(net_id)s "
                "reason: %(exc)s", {
                    'port_id': port['id'],
                    'net_id': network['id'],
                    'switch': switch_info,
                    'exc': e
                })
            raise e
        LOG.info(
            'Port %(port_id)s has been unplugged from network '
            '%(net_id)s on device %(device)s', {
                'port_id': port['id'],
                'net_id': network['id'],
                'device': switch_info
            })
Пример #7
0
    def update_port_postcommit(self, context):
        """Update a port.

        :param context: PortContext instance describing the new
        state of the port, as well as the original state prior
        to the update_port call.

        Called after the transaction completes. Call can block, though
        will block the entire process so care should be taken to not
        drastically affect performance.  Raising an exception will
        result in the deletion of the resource.

        update_port_postcommit is called for all changes to the port
        state. It is up to the mechanism driver to ignore state or
        state changes that it does not know or care about.
        """
        port = context.current
        if self._is_port_bound(port):
            binding_profile = port['binding:profile']
            local_link_information = binding_profile.get(
                'local_link_information')
            local_group_information = binding_profile.get(
                'local_group_information')
            if not local_link_information:
                return
            if local_group_information:
                self._lag_alter_local_link(local_group_information,
                                           local_link_information)
            for switch in local_link_information:
                switch_info = switch.get('switch_info')
                switch_id = switch.get('switch_id')
                switch_device = device_utils.get_switch_device(
                    self.switches,
                    switch_info=switch_info,
                    ngs_mac_address=switch_id)
                if not switch_device:
                    return
                provisioning_blocks.provisioning_complete(
                    context._plugin_context, port['id'], resources.PORT,
                    GENERIC_SWITCH_ENTITY)
        elif self._is_port_bound(context.original):
            # The port has been unbound. This will cause the local link
            # information to be lost, so remove the port from the network on
            # the switch now while we have the required information.
            self._unplug_port_from_network(context.original,
                                           context.network.current)
Пример #8
0
    def _process_subport_payload(self, payload):
        parent_port = payload.parent_port
        binding_profile = parent_port.get('binding:profile')
        trunk_details = parent_port.get('trunk_details')
        network = payload.network

        if not trunk_details:
            raise Exception("Parent port {} is not trunked".format(
                parent_port.id))

        local_link_information = binding_profile['local_link_information']
        local_group_information = binding_profile.get(
            'local_group_information')

        if local_group_information:
            self._lag_alter_local_link(local_group_information,
                                       local_link_information)

        switches = []
        for local_link in local_link_information:
            port_id = local_link.get('port_id')
            switch_info = local_link.get('switch_info')
            switch_id = local_link.get('switch_id')
            switch = device_utils.get_switch_device(self.switches,
                                                    switch_info=switch_info,
                                                    ngs_mac_address=switch_id)
            switches.append(switch)

        changed_seg_ids = [
            subport['segmentation_id'] for subport in payload.subports
        ]
        native_vlan = network['provider:segmentation_id']
        seg_ids = [
            sub_port['segmentation_id']
            for sub_port in trunk_details["sub_ports"]
        ]

        return switches, changed_seg_ids, port_id, seg_ids, native_vlan
Пример #9
0
    def bind_port(self, context):
        """Attempt to bind a port.

        :param context: PortContext instance describing the port

        This method is called outside any transaction to attempt to
        establish a port binding using this mechanism driver. Bindings
        may be created at each of multiple levels of a hierarchical
        network, and are established from the top level downward. At
        each level, the mechanism driver determines whether it can
        bind to any of the network segments in the
        context.segments_to_bind property, based on the value of the
        context.host property, any relevant port or network
        attributes, and its own knowledge of the network topology. At
        the top level, context.segments_to_bind contains the static
        segments of the port's network. At each lower level of
        binding, it contains static or dynamic segments supplied by
        the driver that bound at the level above. If the driver is
        able to complete the binding of the port to any segment in
        context.segments_to_bind, it must call context.set_binding
        with the binding details. If it can partially bind the port,
        it must call context.continue_binding with the network
        segments to be used to bind at the next lower level.

        If the binding results are committed after bind_port returns,
        they will be seen by all mechanism drivers as
        update_port_precommit and update_port_postcommit calls. But if
        some other thread or process concurrently binds or updates the
        port, these binding results will not be committed, and
        update_port_precommit and update_port_postcommit will not be
        called on the mechanism drivers with these results. Because
        binding results can be discarded rather than committed,
        drivers should avoid making persistent state changes in
        bind_port, or else must ensure that such state changes are
        eventually cleaned up.

        Implementing this method explicitly declares the mechanism
        driver as having the intention to bind ports. This is inspected
        by the QoS service to identify the available QoS rules you
        can use with ports.
        """

        port = context.current
        binding_profile = port['binding:profile']
        local_link_information = binding_profile.get('local_link_information')
        if self._is_port_supported(port) and local_link_information:
            switch_info = local_link_information[0].get('switch_info')
            switch_id = local_link_information[0].get('switch_id')
            switch = device_utils.get_switch_device(self.switches,
                                                    switch_info=switch_info,
                                                    ngs_mac_address=switch_id)
            if not switch:
                return
            network = context.network.current
            physnet = network['provider:physical_network']
            switch_physnets = switch._get_physical_networks()
            if switch_physnets and physnet not in switch_physnets:
                LOG.error(
                    "Cannot bind port %(port)s as device %(device)s is "
                    "not on physical network %(physnet)", {
                        'port_id': port['id'],
                        'device': switch_info,
                        'physnet': physnet
                    })
                return
            port_id = local_link_information[0].get('port_id')
            segments = context.segments_to_bind
            # If segmentation ID is None, set vlan 1
            segmentation_id = segments[0].get('segmentation_id') or '1'
            provisioning_blocks.add_provisioning_component(
                context._plugin_context, port['id'], resources.PORT,
                GENERIC_SWITCH_ENTITY)
            LOG.debug("Putting port {port} on {switch_info} to vlan: "
                      "{segmentation_id}".format(
                          port=port_id,
                          switch_info=switch_info,
                          segmentation_id=segmentation_id))
            # Move port to network
            switch.plug_port_to_network(port_id, segmentation_id)
            LOG.info(
                "Successfully bound port %(port_id)s in segment "
                "%(segment_id)s on device %(device)s", {
                    'port_id': port['id'],
                    'device': switch_info,
                    'segment_id': segmentation_id
                })
            context.set_binding(segments[0][api.ID],
                                portbindings.VIF_TYPE_OTHER, {})
Пример #10
0
 def test_get_switch_device_no_match(self):
     self.assertIsNone(
         device_utils.get_switch_device(self.devices, switch_info='C'))
     self.assertIsNone(
         device_utils.get_switch_device(
             self.devices, ngs_mac_address='11:22:33:44:55:66'))
Пример #11
0
 def test_get_switch_device_match_mac_ignore_case(self):
     self.assertEqual(
         device_utils.get_switch_device(
             self.devices,
             switch_info='A',
             ngs_mac_address='AA:BB:CC:DD:EE:FF'), self.devices['B'])
Пример #12
0
    def bind_port(self, context):
        """Attempt to bind a port.

        :param context: PortContext instance describing the port

        This method is called outside any transaction to attempt to
        establish a port binding using this mechanism driver. Bindings
        may be created at each of multiple levels of a hierarchical
        network, and are established from the top level downward. At
        each level, the mechanism driver determines whether it can
        bind to any of the network segments in the
        context.segments_to_bind property, based on the value of the
        context.host property, any relevant port or network
        attributes, and its own knowledge of the network topology. At
        the top level, context.segments_to_bind contains the static
        segments of the port's network. At each lower level of
        binding, it contains static or dynamic segments supplied by
        the driver that bound at the level above. If the driver is
        able to complete the binding of the port to any segment in
        context.segments_to_bind, it must call context.set_binding
        with the binding details. If it can partially bind the port,
        it must call context.continue_binding with the network
        segments to be used to bind at the next lower level.

        If the binding results are committed after bind_port returns,
        they will be seen by all mechanism drivers as
        update_port_precommit and update_port_postcommit calls. But if
        some other thread or process concurrently binds or updates the
        port, these binding results will not be committed, and
        update_port_precommit and update_port_postcommit will not be
        called on the mechanism drivers with these results. Because
        binding results can be discarded rather than committed,
        drivers should avoid making persistent state changes in
        bind_port, or else must ensure that such state changes are
        eventually cleaned up.

        Implementing this method explicitly declares the mechanism
        driver as having the intention to bind ports. This is inspected
        by the QoS service to identify the available QoS rules you
        can use with ports.
        """

        port = context.current
        binding_profile = port['binding:profile']
        local_link_information = binding_profile.get('local_link_information')
        local_group_information = binding_profile.get(
            'local_group_information')
        LOG.debug(local_link_information)
        LOG.debug(local_group_information)
        #if self._is_port_supported(port) and local_link_information:
        if local_link_information:
            switch_info = local_link_information[0].get('switch_info')
            switch_id = local_link_information[0].get('switch_id')
            switch = device_utils.get_switch_device(self.switches,
                                                    switch_info=switch_info,
                                                    ngs_mac_address=switch_id)
            if not switch:
                return
            port_id = local_link_information[0].get('port_id')
            segments = context.segments_to_bind
            segmentation_id = segments[0].get('segmentation_id')
            # If segmentation ID is None, set vlan 1
            if not segmentation_id:
                segmentation_id = '1'
            provisioning_blocks.add_provisioning_component(
                context._plugin_context, port['id'], resources.PORT,
                GENERIC_SWITCH_ENTITY)
            LOG.debug("Putting port {port} on {switch_info} to vlan: "
                      "{segmentation_id}".format(
                          port=port_id,
                          switch_info=switch_info,
                          segmentation_id=segmentation_id))
            # If a request to create dynamic group is arrived
            if (len(local_link_information) > 1):
                #output = switch.create_port_channel(local_group_information.get('name'),segmentation_id)
                switch.vlan_configuration(segmentation_id)
                switch.create_port_channel(local_group_information.get('name'),
                                           segmentation_id)
                port_number_id = re.sub('.*?([0-9]*)$', r'\1',
                                        local_group_information.get('name'))
                #output = switch.create_port_channel(segmentation_id)
                LOG.debug("YYY: {port_number_id}".format(
                    port_number_id=port_number_id))
                for item in local_link_information:
                    i = item.get('port_id')
                    LOG.debug("XXX: {output}".format(output=i))
                    switch.configure_port_channel(i, port_number_id,
                                                  segmentation_id)
                #port_list = switch.show_port_list().splitlines()
                #port_list = [w.replace('interface Port-channel', '') for w in port_list]
                #for item in port_list:
                #    LOG.debug("YYY: {output}".format(output=item))
            else:
                # Move port to network
                switch.plug_port_to_network(port_id, segmentation_id)

            LOG.info(
                "Successfully bound port %(port_id)s in segment "
                " %(segment_id)s on device %(device)s", {
                    'port_id': port['id'],
                    'device': switch_info,
                    'segment_id': segmentation_id
                })
            context.set_binding(segments[0][driver_api.ID],
                                portbindings.VIF_TYPE_OTHER, {})