def _cleanup_definitions(self, vfab_id, vlanid, ports, config, mac,
                             commit=False):
        """Cleanup existing LAG/VLAN/interface definitions.

        @param self  CFABdriver's instance
        @param vfab_id  the string of VFAB ID
        @param vlanid  the string of VLAN ID
        @param ports   string of the ports which is separated by ','
        @param config  string of candidate-config
        @param mac  string of the MAC address
        @param commit  the boolean whether executes commit or not
        @return  A string of modified ifgroups for vfab vlan or None
        """

        self._dissociate_mac_from_port_profile(vfab_id, vlanid, mac,
                                               config=config,
                                               do_not_commit=True)
        lag_id = _get_associated_lag_id(ports, config)
        commit_interface = True if (commit and not lag_id) else False
        self._clear_interfaces(ports, commit=commit_interface)
        if commit_interface:
            LOG.debug(_('Skip clearing VLAN and LAG.'))
            return None
        modified = self._clear_vlans(vfab_id, ports, config, lag_id=lag_id)
        if lag_id:
            LOG.debug(_('Found LAG%s definiton and clear.'), lag_id)
            self._clear_lag(vfab_id, lag_id, ports, config, commit=commit)
        return modified.get(str(vlanid), None)
 def _validate_pprofile_prefix(self):
     if len(self._pprofile_prefix) > (28 if self._share_pprofile else 15):
         raise ValueError(_("pprofile_prefix is too long."))
     if (self._pprofile_prefix.find('"') >= 0 or
             self._pprofile_prefix.find("|") >= 0 or
             self._pprofile_prefix.find("?") >= 0):
         raise ValueError(_("pprofile_prefix contains illegal character."))
    def _setup_vfab_vlan(self, vfab_id, vlanid, ifgroup_id, config, ifg=None,
                         port_type=_EP, vlan_type='untag', commit=False):
        """Setup VFAB VLAN configuration."""

        # Judge the result of cleanup process.
        #     ifg is None
        #         'ifgroup' for vfab vlan hasn't changed at all.
        #     ifg is ''(Empty string)
        #         The definition of vfab vlan has been deleted in cleanup.
        #     ifg is String(Not empty)
        #         'ifgroup' for vfab vlan has been changed in cleanup.
        modified = True if ifg is not None else False
        ifgroups = ifg if modified else _get_ifgroups_of_vfab_vlan(
                                            vfab_id, vlanid, config)
        # Need to re-define for the vfab vlan.
        if modified and ifg is '':
            ifgroups = None
        if _is_ifgroup_included(ifgroup_id, ifgroups):
            LOG.debug(_("ifgroup %(if_id)s has already configured"
                        "in %(ifgs)s"), dict(if_id=ifgroup_id, ifgs=ifgroups))
        elif ifgroups is None:
            ifgroups = str(ifgroup_id)
        else:
            ifgroups += "," + str(ifgroup_id)

        cmds = [
            "vfab {vfab} vlan {vlan} {port_type} {vlan_type} {ifgroup}".format(
                vfab=vfab_id, vlan=vlanid, port_type=port_type,
                vlan_type=vlan_type, ifgroup=ifgroups)]
        self.mgr.configure(cmds, commit=commit)
def _get_all_vfab_vlans_and_ifgroups(vfab_id, config, vlan_type='untag'):
    """Gets all VFAB VLAN definitions and ifgroups.

        @param vfab_id  the string of VFAB ID
        @param config the string of candidate-config
        @param vlan_type 'untag(default)' or 'tag'.
        @return the string of ifgroups otherwise None
    """
    match = re.findall(_VFAB_VLANS.format(v=vfab_id, vlan_type=vlan_type),
                       config, re.MULTILINE)
    result = dict(match)
    if result:
        LOG.debug(_('VFAB(%(vfab)s){VLANID: ifgroups}:%(result)s'),
            dict(vfab=vfab_id, result=result))
    else:
        LOG.debug(_('VLAN and ifgroups not found.'))
    return result
    def _clear_vlans(self, vfab_id, ports, config, port_type=_EP,
                    vlan_type='untag', lag_id=None, commit=False):
        """Clear all VLAN definitions with specified ports.

        @param self  CFABdriver's instance
        @param vfab_id  the string of VFAB ID
        @param ports  a string of the ports which is separated by ','
        @param config a string of a candidate-config
        @return None or string of the modified ifgroups separated by ','
        """

        # (yushiro): ifgroup won't delete because it can not determine
        #            whether ifgroup is created by plugin or not.
        indices = search_ifgroup_indices(ports, config, lag_id=lag_id)
        vlan_ifgs = _get_all_vfab_vlans_and_ifgroups(vfab_id, config,
                                                     vlan_type='untag')
        updated_vlan_ifgs = copy.deepcopy(vlan_ifgs)
        cmds = []
        for vlanid in sorted(vlan_ifgs.keys()):
            vlan = str(vlanid)
            is_delete = False
            # Target ifgroup_ids exists but vfab vlan definition does not exist
            # or ifgroup_id doesn't exist but vfab vlan definition exists.
            if None in [vlan_ifgs[vlan]] or not indices:
                LOG.debug(_("ifgroup with %(p)s for VLAN(%(v)s)has already"
                            "deleted. Skip clear_vlan."), dict(p=ports,
                                                               v=vlanid))
                continue
            eliminated = fj_util.eliminate_val(vlan_ifgs[vlan], indices)
            updated_vlan_ifgs[vlan] = eliminated
            # VLAN is configured with the only ifgroup_id
            if not eliminated:
                is_delete = True

            common_def = "vfab {vfab} vlan {vlan} {port_type} {vlan_type}"
            # Delete VFAB VLAN definition
            if is_delete:
                command = "no" + " " + common_def
                cmds.append(command.format(vfab=vfab_id, vlan=vlanid,
                                           port_type=port_type,
                                           vlan_type=vlan_type))
            # Reject ifgroup_id from VFAB VLAN definition
            else:
                command = common_def + " " + "{ifgroup}"
                cmds.append(command.format(vfab=vfab_id, vlan=vlanid,
                                           port_type=port_type,
                                           vlan_type=vlan_type,
                                           ifgroup=eliminated))
        self.mgr.configure(cmds, commit=commit)
        return updated_vlan_ifgs
def search_ifgroup_indices(ports, candidate_config, lag_id=None):
    """Search ifgroup ids with specified ports."""

    reg = r"^ifgroup\s+(\d+)\s+ether\s+{ports}$".format(ports=ports)
    if lag_id:
        domain_id = _get_domain_id(ports)
        reg = r"^ifgroup\s+(\d+)\s+{if_type}\s+{domain_id}\s+{lag_id}$".format(
                  if_type=_LAG, domain_id=domain_id, lag_id=lag_id)
    match = re.findall(reg, candidate_config, re.MULTILINE)
    if match:
        ifgroup_indices = sorted([int(m) for m in match])
        LOG.debug(_('Found ifgroup for port(%(p)s):%(ifg)s'),
            dict(p=ports, ifg=ifgroup_indices))
        return ifgroup_indices
    return []
def _get_associated_lag_id(ports, config):
    """Get lag_id which is associated to the ports."""

    ids = []
    interfaces = ports.split(",")
    for port in interfaces:
        match = re.search(
            r'^interface\s+{port}$\n((?:\s+.+\n)'
            r'*(\s+type\s+{port_type}\s+(\d+))(?:\s+.+\n)*)\s+exit$'.format(
                port=port, port_type='linkaggregation'), config, re.MULTILINE)
        if match:
            ids.append(match.group(3))
    lag_ids = list(set(ids))
    if not lag_ids:
        return None
    if len(lag_ids) > 1:
        LOG.warning(
            _LW("Each port%(ports)s has different LAG ids(%(lag_ids)s)"),
            dict(ports=ports, lag_ids=lag_ids))
    LOG.debug(_("Associated LAG%(lag_ids)s with interfaces:%(ports)s"),
        dict(lag_ids=lag_ids, ports=ports))
    return sorted(lag_ids)[0]
def eliminate_val(source, reject):
    """Eliminate specified value from range value.

    ex. source='1,2,3-10', reject=[1], result: '2,3-10'
    @param source a string of range definition separated with ","
           ex. "1,2,3" or "1-5"(same as "1,2,3,4,5")
    @param reject a list of integer to reject. ex. [1, 2]
    @return eliminated a string of eliminated value separated with ","
    """
    if source is None:
        return
    values = [str(i) for i in reject]
    rejected = source.split(',')
    found = False
    for val in values:
        for target in rejected:
            m = RANGE_DEFINITION.match(target)
            if m:
                low = m.group(1)
                high = m.group(2)
                if val in target:
                    rejected.remove(target)
                    # matches the lowest one
                    if (val == low):
                        # Case: source is "1-2" and target is "1"
                        if ((int(val) + 1) == int(high)):
                            rejected.append(high)
                        else:
                            rejected.append(str(int(val) + 1) + "-" + high)
                            found = True
                            break
                    # matches the highest one
                    else:
                        # Ex. source is "1-2" and target is "2"
                        if ((int(val) - 1) == int(low)):
                            rejected.append(low)
                        else:
                            rejected.append(low + "-" + str(int(val) - 1))
                        found = True
                        break
                # matches between lower one and higher one
                elif (int(low) < int(val) and int(val) < int(high)):
                    rejected.remove(target)
                    # Ex. source is "1-n" and target is "2"
                    if ((int(val) - 1) == int(low)):
                        rejected.append(low)
                        # Ex. source is "1-3" and target is "2"
                        if ((int(val) + 1) == int(high)):
                            rejected.append(high)
                        # Ex. source is "1-4" and target is "2"
                        else:
                            rejected.append(str(int(val) + 1) + "-" + high)
                    # Ex. source is "n-5" and target is "4"(n is NOT "3")
                    elif ((int(val) + 1) == int(high)):
                        rejected.append(high)
                        rejected.append(low + "-" + str(int(val) - 1))
                    # Ex. source is "1-5" and target is "3"
                    else:
                        rejected.append(low + "-" + str(int(val) - 1))
                        rejected.append(str(int(val) + 1) + "-" + high)
                    found = True
                    break
            # source is not defined with range "-"
            elif val == target:
                rejected.remove(target)
                found = True
                break
    if not found:
        LOG.debug(_('Reject target doesn\'t exist.'))
    return ','.join(rejected)