def _load_dhcp_if_inst(self):
        if not self.dhcp_service:
            return
        drv_type = self._get_driver_type(self.dhcp_service[omni_const.OMNI_CFG_DEV_TYPE])
        if self.omniswitch_6xx(self.dhcp_service):
            if self.device_access_rest(self.dhcp_service):
                LOG.info("ALERT: This device (%s) does not support REST interface.\
                       Instead TELNET interface will be used!", self.dhcp_service[omni_const.OMNI_CFG_DEV_IP])
            self.dhcp_if_inst = OmniSwitchTelnetDriver(self.dhcp_service[omni_const.OMNI_CFG_DEV_IP], drv_type,
                                                       self.dhcp_service[omni_const.OMNI_CFG_DEV_LOGIN],
                                                       self.dhcp_service[omni_const.OMNI_CFG_DEV_PASSWORD],
                                                       self.dhcp_service[omni_const.OMNI_CFG_DEV_PROMPT])
        else:  # for both 7XX and 8XX
            if self.device_access_rest(self.dhcp_service):
                self.dhcp_if_inst = OmniSwitchRestfulDriver(self.dhcp_service[omni_const.OMNI_CFG_DEV_IP], drv_type,
                                                            self.dhcp_service[omni_const.OMNI_CFG_DEV_LOGIN],
                                                            self.dhcp_service[omni_const.OMNI_CFG_DEV_PASSWORD])
            else:
                self.dhcp_if_inst = OmniSwitchTelnetDriver(self.dhcp_service[omni_const.OMNI_CFG_DEV_IP], drv_type,
                                                           self.dhcp_service[omni_const.OMNI_CFG_DEV_LOGIN],
                                                           self.dhcp_service[omni_const.OMNI_CFG_DEV_PASSWORD])

        LOG.info("_load_dhcp_if_inst done!")
class OmniSwitchDevicePluginV2(object):

    """Name:     OmniSwitchDevicePluginV2
    Description: OpenStack Neutron plugin for Alcatel-Lucent OmniSwitch Data networking
                 devices.

    Details:     It is one of the device plugin in the OmniSwitch multi-plugin design.
                 This implements the Neutron Network APIs (ver 2.0) for OmniSwitch
                 devices. This is instantiated by the OmniSwitchNetworkPluginV2 which is
                 core plugin for Neutron server. This uses the device specific
                 communication mechanism for interfacing with different types of
                 OmniSwitch devices.
    """

    def __init__(self):

        # list of omni devices from 'omni_network_plugin.ini' file
        self.edge_device_list = []
        # list of device driver instances (ddi) corresponding to each of the device in edge_device_list
        self.edge_ddi_list = {}
        # list of omni core devices from 'omni_network_plugin.ini' file
        self.core_device_list = []
        # list of device driver instances (ddi) corresponding to each of the device in core_device_list
        self.core_ddi_list = {}
        # details of the edge switch which is connected to network node where dhcp-server is running
        self.dhcp_service = []
        self.dhcp_if_inst = None
        # interval(in secs) at which the config will be saved in the switches
        self.switch_save_config_interval = 0

        # some init general init status vars
        self.db_option = None
        self.init_config_applied = None

        # used for tracking whether to do write memory in the switch or not
        self.edge_config_changed = 0
        self.core_config_changed = 0

        self._load_config()
        self._load_edge_ddi()
        self._load_core_ddi()
        self._load_dhcp_if_inst()
        self._start_save_config_thread()

    def _load_config(self):
        """loads the OmniSwitch device list from the config file and instantiates
        the appropriate device specific driver to communicate with it.
        """

        # OMNI_EDGE_DEVICES
        for device in cfg.CONF.ml2_ale_omniswitch.omni_edge_devices:
            device_specs = [x.strip() for x in device.split(':')]
            self.edge_device_list.append(device_specs)

        # OMNI_CORE_DEVICES
        if cfg.CONF.ml2_ale_omniswitch.omni_core_devices != [] and cfg.CONF.ml2_ale_omniswitch.omni_core_devices != ['']:
            for device in cfg.CONF.ml2_ale_omniswitch.omni_core_devices:
                device_specs = [x.strip() for x in device.split(':')]
                self.core_device_list.append(device_specs)

        # DHCP_SERVER_INTERFACE
        self.dhcp_service = [x.strip() for x in cfg.CONF.ml2_ale_omniswitch.dhcp_server_interface.split(':')]
        if self.dhcp_service == [] or self.dhcp_service == ['']:
            self.dhcp_service = None

        self.switch_save_config_interval = cfg.CONF.ml2_ale_omniswitch.switch_save_config_interval
        if (self.switch_save_config_interval < omni_const.OMNI_CFG_SAVE_INTERVAL_MIN or
           self.switch_save_config_interval > omni_const.OMNI_CFG_SAVE_INTERVAL_MAX):
            LOG.info("switch_save_config_interval %d is out of valid range(%d - %d)... default to %d",
                     self.switch_save_config_interval,
                     omni_const.OMNI_CFG_SAVE_INTERVAL_MIN,
                     omni_const.OMNI_CFG_SAVE_INTERVAL_MAX,
                     omni_const.OMNI_CFG_SAVE_INTERVAL_MIN)
            self.switch_save_config_interval = omni_const.OMNI_CFG_SAVE_INTERVAL_MIN

    def _load_edge_ddi(self):
        for device in self.edge_device_list:
            drv_type = self._get_driver_type(device[omni_const.OMNI_CFG_DEV_TYPE])

            if self.omniswitch_6xx(device):
                if self.device_access_rest(device):
                    LOG.info("ALERT: This device (%s) does not support REST interface.\
                          Instead TELNET interface will be used!", device[omni_const.OMNI_CFG_DEV_IP])
                self.edge_ddi_list.setdefault(device[omni_const.OMNI_CFG_DEV_IP],
                                              OmniSwitchTelnetDriver(device[omni_const.OMNI_CFG_DEV_IP], drv_type,
                                                                     device[omni_const.OMNI_CFG_DEV_LOGIN],
                                                                     device[omni_const.OMNI_CFG_DEV_PASSWORD],
                                                                     device[omni_const.OMNI_CFG_DEV_PROMPT]))
            # for both 7XX and 8XX
            elif self.switch_access_rest(device):
                self.edge_ddi_list.setdefault(device[omni_const.OMNI_CFG_DEV_IP],
                                              OmniSwitchRestfulDriver(device[omni_const.OMNI_CFG_DEV_IP], drv_type,
                                                                      device[omni_const.OMNI_CFG_DEV_LOGIN],
                                                                      device[omni_const.OMNI_CFG_DEV_PASSWORD]))
            else:
                self.edge_ddi_list.setdefault(device[omni_const.OMNI_CFG_DEV_IP],
                                              OmniSwitchTelnetDriver(device[omni_const.OMNI_CFG_DEV_IP], drv_type,
                                                                     device[omni_const.OMNI_CFG_DEV_LOGIN],
                                                                     device[omni_const.OMNI_CFG_DEV_PASSWORD]))

        LOG.info("_load_edge_ddi done!")

    def _load_core_ddi(self):
        if len(self.core_device_list) == 0:
            return

        for device in self.core_device_list:
            drv_type = self._get_driver_type(device[omni_const.OMNI_CFG_DEV_TYPE])

            if self.omniswitch_6xx(device):
                if self.device_access_rest(device):
                    LOG.info("ALERT: This device (%s) does not support REST interface.\
                           Instead TELNET interface will be used!", device[omni_const.OMNI_CFG_DEV_IP])
                self.core_ddi_list.setdefault(device[omni_const.OMNI_CFG_DEV_IP],
                                              OmniSwitchTelnetDriver(device[omni_const.OMNI_CFG_DEV_IP], drv_type,
                                                                     device[omni_const.OMNI_CFG_DEV_LOGIN],
                                                                     device[omni_const.OMNI_CFG_DEV_PASSWORD],
                                                                     device[omni_const.OMNI_CFG_DEV_PROMPT]))
            # for both 7XX and 8XX
            elif self.switch_access_rest(device):
                self.core_ddi_list.setdefault(device[omni_const.OMNI_CFG_DEV_IP],
                                              OmniSwitchRestfulDriver(device[omni_const.OMNI_CFG_DEV_IP], drv_type,
                                                                      device[omni_const.OMNI_CFG_DEV_LOGIN],
                                                                      device[omni_const.OMNI_CFG_DEV_PASSWORD]))
            else:
                self.core_ddi_list.setdefault(device[omni_const.OMNI_CFG_DEV_IP],
                                              OmniSwitchTelnetDriver(device[omni_const.OMNI_CFG_DEV_IP], drv_type,
                                                                     device[omni_const.OMNI_CFG_DEV_LOGIN],
                                                                     device[omni_const.OMNI_CFG_DEV_PASSWORD]))
        LOG.info("_load_core_ddi done!")

    def _load_dhcp_if_inst(self):
        if not self.dhcp_service:
            return
        drv_type = self._get_driver_type(self.dhcp_service[omni_const.OMNI_CFG_DEV_TYPE])
        if self.omniswitch_6xx(self.dhcp_service):
            if self.device_access_rest(self.dhcp_service):
                LOG.info("ALERT: This device (%s) does not support REST interface.\
                       Instead TELNET interface will be used!", self.dhcp_service[omni_const.OMNI_CFG_DEV_IP])
            self.dhcp_if_inst = OmniSwitchTelnetDriver(self.dhcp_service[omni_const.OMNI_CFG_DEV_IP], drv_type,
                                                       self.dhcp_service[omni_const.OMNI_CFG_DEV_LOGIN],
                                                       self.dhcp_service[omni_const.OMNI_CFG_DEV_PASSWORD],
                                                       self.dhcp_service[omni_const.OMNI_CFG_DEV_PROMPT])
        else:  # for both 7XX and 8XX
            if self.device_access_rest(self.dhcp_service):
                self.dhcp_if_inst = OmniSwitchRestfulDriver(self.dhcp_service[omni_const.OMNI_CFG_DEV_IP], drv_type,
                                                            self.dhcp_service[omni_const.OMNI_CFG_DEV_LOGIN],
                                                            self.dhcp_service[omni_const.OMNI_CFG_DEV_PASSWORD])
            else:
                self.dhcp_if_inst = OmniSwitchTelnetDriver(self.dhcp_service[omni_const.OMNI_CFG_DEV_IP], drv_type,
                                                           self.dhcp_service[omni_const.OMNI_CFG_DEV_LOGIN],
                                                           self.dhcp_service[omni_const.OMNI_CFG_DEV_PASSWORD])

        LOG.info("_load_dhcp_if_inst done!")

    def _start_save_config_thread(self):
        SaveConfigThread(self).start()

    def _config_vpa_core(self, vlan_id, action, net_name=''):
        pool = Pool(size=(len(self.core_device_list) + len(self.edge_device_list)))

        def config_vpa_core_device(device):
            if device[omni_const.OMNI_CFG_DEV_CORE_IF].strip():
                if action == omni_const.OMNI_CFG_CREATE:
                    self.core_ddi_list[device[omni_const.OMNI_CFG_DEV_IP]].create_vlan_locked(vlan_id, net_name)
                    if_list = device[omni_const.OMNI_CFG_DEV_CORE_IF].split(' ')
                    for port in if_list:
                        self.core_ddi_list[device[omni_const.OMNI_CFG_DEV_IP]].create_vpa(vlan_id, port)
                elif action == omni_const.OMNI_CFG_UPDATE:
                    self.core_ddi_list[device[omni_const.OMNI_CFG_DEV_IP]].update_vlan_locked(vlan_id, net_name)
                elif action == omni_const.OMNI_CFG_DELETE:
                    LOG.info("vpa core delete vlan!")
                    self.core_ddi_list[device[omni_const.OMNI_CFG_DEV_IP]].delete_vlan_locked(vlan_id)

        def config_vpa_edge_device(device):
            if device[omni_const.OMNI_CFG_DEV_EDGE2CORE_IF].strip():
                if_list = device[omni_const.OMNI_CFG_DEV_EDGE2CORE_IF].split(' ')
                for port in if_list:
                    self.edge_ddi_list[device[omni_const.OMNI_CFG_DEV_IP]].create_vpa(vlan_id, port)

        output = list()
        for result in pool.imap(config_vpa_core_device, self.core_device_list):
            output.append(result)
        if action == omni_const.OMNI_CFG_CREATE:
            for result in pool.imap(config_vpa_edge_device, self.edge_device_list):
                output.append(result)
        return True

    def _config_vpa_edge(self, edge_ddi_obj, vlan_id, action):
        compute_if = self._get_edge2compute_if(edge_ddi_obj.get_ip())
        if compute_if.strip():
            if_list = compute_if.split(' ')
            for port in if_list:
                if action == omni_const.OMNI_CFG_CREATE:
                    edge_ddi_obj.create_vpa(vlan_id, port)
                elif action == omni_const.OMNI_CFG_DELETE:
                    edge_ddi_obj.delete_vpa(vlan_id, port)

        return True

    """
       General System APIs within Device plugin
    """

    def save_core_config(self, immediate=0):
        if immediate == 0:
            self.core_config_changed = 1
            return

        pool = Pool(size=len(self.core_device_list))

        def m_save_core_config(device):
            ddi_obj = self.core_ddi_list[device[omni_const.OMNI_CFG_DEV_IP]]
            self._invoke_driver_api(ddi_obj, "save_config", [])

        output = list()
        for result in pool.imap(m_save_core_config, self.core_device_list):
            output.append(result)

        self.core_config_changed = 0
        return

    def save_edge_config(self, immediate=0):
        if immediate == 0:
            self.edge_config_changed = 1
            return

        pool = Pool(size=len(self.edge_device_list))

        def m_save_edge_config(device):
            ddi_obj = self.edge_ddi_list[device[omni_const.OMNI_CFG_DEV_IP]]
            self._invoke_driver_api(ddi_obj, "save_config", [])

        output = list()
        for result in pool.imap(m_save_edge_config, self.edge_device_list):
            output.append(result)

        self.edge_config_changed = 0
        return

    def save_config(self):
        if self.core_config_changed == 1:
            self.save_core_config(1)

        if self.edge_config_changed == 1:
            self.save_edge_config(1)

    """ Neutron Core API 2.0 """

    def create_network(self, mech_context):
        ret = False
        if self.cn_edge_config(mech_context):
            if self.cn_core_config(mech_context):
                ret = self.cn_dhcp_config(mech_context)
        return ret

    def update_network(self, mech_context):
        self.un_edge_config(mech_context)
        self.un_core_config(mech_context)
        self.un_dhcp_config(mech_context)
        return True

    def delete_network(self, mech_context):
        self.dn_dhcp_config(mech_context)
        self.dn_core_config(mech_context)
        self.dn_edge_config(mech_context)
        return True

    def update_subnet(self, mech_context):
        return True

    def create_subnet(self, mech_context):
        return True

    def delete_subnet(self, mech_context):
        return True

    def delete_port(self, mech_context):
        return True

    def update_port(self, mech_context):
        return True

    def create_port(self, mech_context):
        return True

    """
       Wrapper for Core API functional routines
    """
    def cn_edge_config(self, mech_context):
        ret = True
        network = mech_context.current
        segments = mech_context.network_segments

        # currently supports only one segment per network
        segment = segments[0]
        vlan_id = segment['segmentation_id']
        network_name = network['name']

        def m_cn_edge_config(ddi_obj):
            if self._invoke_driver_api(ddi_obj, "create_network", [vlan_id, network_name]):
                res = self._config_vpa_edge(ddi_obj, vlan_id, omni_const.OMNI_CFG_CREATE)
            else:
                res = False
            return res

        pool = Pool(size=len(self.edge_ddi_list.items()))
        output = list()

        ddi_list = [item[1] for item in self.edge_ddi_list.items()]
        for result in pool.imap(m_cn_edge_config, ddi_list):
            output.append(result)

        if False in output:
            # some error in create network, roll back network creation
            self.delete_network(mech_context)  # vad: optimize only for that switch
            self.save_edge_config()
            ret = False

        return ret

    def cn_core_config(self, mech_context):
        ret = True
        network = mech_context.current
        segments = mech_context.network_segments

        # currently supports only one segment per network
        segment = segments[0]
        vlan_id = segment['segmentation_id']
        network_name = network['name']

        if not self._config_vpa_core(vlan_id, omni_const.OMNI_CFG_CREATE, network_name):
                # some error in vpa creation, roll back network creation
                self.delete_network(mech_context)
                self.save_edge_config()
                ret = False
        else:
            self.save_core_config()
        return ret

    def cn_dhcp_config(self, mech_context):
        ret = True
        segments = mech_context.network_segments
        # currently supports only one segment per network
        segment = segments[0]
        vlan_id = segment['segmentation_id']

        if self.dhcp_if_inst:
            ret = self.dhcp_if_inst.create_vpa(vlan_id, self.dhcp_service[omni_const.OMNI_CFG_DHCP_SERVER_IF])
            if not ret:
                # some error in vpa creation for dhcp, roll back network creation
                self.delete_network(mech_context)
                ret = False

        self.save_edge_config()
        return ret

    def un_edge_config(self, mech_context):
        ret = True
        network = mech_context.current
        segments = mech_context.network_segments

        # currently supports only one segment per network
        segment = segments[0]
        vlan_id = segment['segmentation_id']
        network_name = network['name']

        if network_name == '':
            LOG.error("un_edge_config: update network: network cannot be the empty string!")
            return False

        def m_un_edge_config(ddi_obj):
            res = True
            if not self._invoke_driver_api(ddi_obj, "update_network", [vlan_id, network_name]):
                res = False
            if not res:
                LOG.info("update network edge failed")
                return res

        output = list()
        pool = Pool(size=len(self.edge_ddi_list.items()))
        ddi_list = [item[1] for item in self.edge_ddi_list.items()]

        for result in pool.imap(m_un_edge_config, ddi_list):
            output.append(result)
        if False in output:
            ret = False

        self.save_edge_config()
        return ret

    def un_core_config(self, mech_context):
        ret = True
        network = mech_context.current
        segments = mech_context.network_segments

        # currently supports only one segment per network
        segment = segments[0]
        vlan_id = segment['segmentation_id']
        network_name = network['name']

        if network_name == '':
            LOG.error("un_core_config: update network: network cannot be the empty string!")
            return False

        if not self._config_vpa_core(vlan_id, omni_const.OMNI_CFG_UPDATE, network_name):
            LOG.error("un_core_config: update network core failed")
            ret = False
        else:
            self.save_core_config()
        return ret

    def un_dhcp_config(self, mech_context):
        ret = True
        if not self.dhcp_if_inst:
            return ret

        network = mech_context.current
        segments = mech_context.network_segments

        # currently supports only one segment per network
        segment = segments[0]
        vlan_id = segment['segmentation_id']
        network_name = network['name']

        if network_name == '':
            LOG.error("un_dhcp_config: network cannot be the empty string!")
            return False

        if not self._invoke_driver_api(self.dhcp_if_inst, "update_network", [vlan_id, network_name]):
            LOG.error("un_dhcp_config: update network failed!")
            ret = False

        self.save_edge_config()
        return ret

    def dn_edge_config(self, mech_context):
        ret = True
        segments = mech_context.network_segments

        # currently supports only one segment per network
        segment = segments[0]
        vlan_id = segment['segmentation_id']

        def m_dn_edge_config_vlan(ddi_obj):
            self._config_vpa_edge(ddi_obj, vlan_id, omni_const.OMNI_CFG_DELETE)
            self._invoke_driver_api(ddi_obj, "delete_network", [vlan_id])

        pool = Pool(size=len(self.edge_ddi_list.items()))
        output = list()
        ddi_list = [item[1] for item in self.edge_ddi_list.items()]
        for result in pool.imap(m_dn_edge_config_vlan, ddi_list):
            output.append(result)

        self.save_edge_config()
        return ret

    def dn_core_config(self, mech_context):
        ret = True
        segments = mech_context.network_segments
        # currently supports only one segment per network
        segment = segments[0]
        vlan_id = segment['segmentation_id']

        if not self._config_vpa_core(vlan_id, omni_const.OMNI_CFG_DELETE):
            ret = False
        else:
            self.save_core_config()
        return ret

    def dn_dhcp_config(self, mech_context):
        segments = mech_context.network_segments
        # currently supports only one segment per network
        segment = segments[0]
        vlan_id = segment['segmentation_id']

        if self.dhcp_if_inst:
            return self.dhcp_if_inst.delete_vpa(vlan_id, self.dhcp_service[omni_const.OMNI_CFG_DHCP_SERVER_IF])
        return True

    """
       Utility routines related to CONFIG
    """
    def _get_edge2compute_if(self, dev_ip):
        for device in self.edge_device_list:
            if device[omni_const.OMNI_CFG_DEV_IP] == dev_ip:
                return device[omni_const.OMNI_CFG_DEV_EDGE2COMPUTE_IF]

    def _get_driver_type(self, switch_type):
        if switch_type == omni_const.OMNISWITCH_OS6860:
            return omni_const.OMNISWITCH_8XX
        elif switch_type == omni_const.OMNISWITCH_OS6900 or switch_type == omni_const.OMNISWITCH_OS10K:
            return omni_const.OMNISWITCH_7XX
        elif (switch_type == omni_const.OMNISWITCH_OS6850E or
              switch_type == omni_const.OMNISWITCH_OS6855 or
              switch_type == omni_const.OMNISWITCH_OS6450 or
              switch_type == omni_const.OMNISWITCH_OS9000):
            return omni_const.OMNISWITCH_6XX

    def _get_switch_access_method(self, switch_access_method):
        return switch_access_method if switch_access_method != "" else omni_const.OMNI_CFG_SWITCH_ACCESS_TELNET

    def _invoke_driver_api(self, drvobj, function_name, args):
        # return thread.start_new_thread(getattr(drvobj, function_name), tuple(args))
        return getattr(drvobj, function_name)(*args)

    def omniswitch_8xx(self, device):
        drv_type = self._get_driver_type(device[omni_const.OMNI_CFG_DEV_TYPE])
        return drv_type == omni_const.OMNISWITCH_8XX

    def omniswitch_7xx(self, device):
        drv_type = self._get_driver_type(device[omni_const.OMNI_CFG_DEV_TYPE])
        return drv_type == omni_const.OMNISWITCH_7XX

    def omniswitch_6xx(self, device):
        drv_type = self._get_driver_type(device[omni_const.OMNI_CFG_DEV_TYPE])
        return drv_type == omni_const.OMNISWITCH_6XX

    def device_access_rest(self, device):
        return device[omni_const.OMNI_CFG_DEV_ACCESS_METHOD] == omni_const.OMNI_CFG_SWITCH_ACCESS_REST

    def device_access_telnet(self, device):
        return device[omni_const.OMNI_CFG_DEV_ACCESS_METHOD] == omni_const.OMNI_CFG_SWITCH_ACCESS_TELNET

    def switch_access_rest(self, device):
        switch_access_method = self._get_switch_access_method(device[omni_const.OMNI_CFG_DEV_ACCESS_METHOD])
        return switch_access_method == omni_const.OMNI_CFG_SWITCH_ACCESS_REST

    def switch_access_telnet(self, device):
        switch_access_method = self._get_switch_access_method(device[omni_const.OMNI_CFG_DEV_ACCESS_METHOD])
        return switch_access_method == omni_const.OMNI_CFG_SWITCH_ACCESS_TELNET