Configure the track property of the vrrp

        Notes:
            set_tracks takes a list of tracked objects which are
            to be set on the virtual router. An empty list will remove
            any existing tracked objects from the vrrp. A list containing
            track entries configures the virtual router to track only the
            objects specified in the list - any existing tracked objects
            on the vrrp not included in the list will be removed.

        Args:
            name (string): The interface to configure.
            vrid (integer): The vrid number for the vrrp to be managed.
            tracks (list): A list of track definition dictionaries. Each
                dictionary is a definition of a tracked object in one
                of the two formats::

                    {'name': tracked_object_name,
                     'action': 'shutdown'}
                    {'name': tracked_object_name,
                     'action': 'decrement',
                     'amount': amount_of_decrement}

            run (boolean): Set to True to execute the command, False to
                return a string with the formatted command.

        Returns:
            If run is True, returns True if the command executed successfully,
            error if failure.

            If run is False, returns the formatted command string which can
            be passed to the node

def set_tracks(self, name, vrid, tracks, run=True):
        """Configure the track property of the vrrp

        Notes:
            set_tracks takes a list of tracked objects which are
            to be set on the virtual router. An empty list will remove
            any existing tracked objects from the vrrp. A list containing
            track entries configures the virtual router to track only the
            objects specified in the list - any existing tracked objects
            on the vrrp not included in the list will be removed.

        Args:
            name (string): The interface to configure.
            vrid (integer): The vrid number for the vrrp to be managed.
            tracks (list): A list of track definition dictionaries. Each
                dictionary is a definition of a tracked object in one
                of the two formats::

                    {'name': tracked_object_name,
                     'action': 'shutdown'}
                    {'name': tracked_object_name,
                     'action': 'decrement',
                     'amount': amount_of_decrement}

            run (boolean): Set to True to execute the command, False to
                return a string with the formatted command.

        Returns:
            If run is True, returns True if the command executed successfully,
            error if failure.

            If run is False, returns the formatted command string which can
            be passed to the node

        """

        cmds = []

        # Get the current set of tracks defined for the vrrp
        curr_tracks = []
        vrrps = self.get(name)
        if vrrps and vrid in vrrps:
            curr_tracks = vrrps[vrid]['track']

        # Determine which tracked objects are in both lists using
        # sets of temporary strings built from the track specifications
        unset = '_none_'
        tracks_set = []
        for track in tracks:
            keys = track.keys()

            # Validate no extraneous keys in track definition
            err_keys = set(keys).difference(('name', 'action', 'amount'))
            if err_keys:
                err_keys = ', '.join(err_keys)
                raise ValueError("Error found in vrrp property 'track': "
                                 "unknown key(s) '%s' found. Valid keys are "
                                 "name, action, and amount" % err_keys)

            # Validate required keys in track definition
            if not set(keys).issuperset(('name', 'action')):
                raise ValueError("Error found in vrrp property 'track': "
                                 "track definition must contain 'name' and "
                                 "'action' keys")

            tr_obj = track['name']
            action = track['action']
            amount = track['amount'] if 'amount' in track else unset

            # Validate values in track definition
            error = False
            if action not in ('shutdown', 'decrement'):
                error = True
            if action == 'shutdown' and amount != unset:
                error = True
            if amount != unset and not str(amount).isdigit():
                error = True
            if error:
                raise ValueError("Error found in vrrp property 'track'. "
                                 "See documentation for format specification.")

            tid = "%s   %s   %s" % (tr_obj, action, amount)
            tracks_set.append(tid)

        curr_set = []
        for track in curr_tracks:
            tr_obj = track['name']
            action = track['action']
            amount = track['amount'] if 'amount' in track else unset

            # Validate track definition
            error = False
            if action not in ('shutdown', 'decrement'):
                error = True
            if action == 'shutdown' and amount != unset:
                error = True
            if amount != unset and not str(amount).isdigit():
                error = True
            if error:
                raise ValueError("Error found in vrrp property 'track'. "
                                 "See documentation for format specification.")

            tid = "%s   %s   %s" % (tr_obj, action, amount)
            curr_set.append(tid)

        intersection = list(set(tracks_set) & set(curr_set))

        # Delete the intersection from both lists to determine which
        # track definitions need to be added or removed from the vrrp
        remove = list(set(curr_set) - set(intersection))
        add = list(set(tracks_set) - set(intersection))

        # Build the commands to add and remove the tracked objects
        for track in remove:
            match = re.match(r'(\S+)\s+(\S+)\s+(\S+)', track)
            if match:
                (tr_obj, action, amount) = \
                    (match.group(1), match.group(2), match.group(3))

                if amount == unset:
                    amount = ''
                t_cmd = ("no vrrp %d track %s %s %s"
                         % (vrid, tr_obj, action, amount))
                cmds.append(t_cmd.rstrip())

        for track in add:
            match = re.match(r'(\S+)\s+(\S+)\s+(\S+)', track)
            if match:
                (tr_obj, action, amount) = \
                    (match.group(1), match.group(2), match.group(3))

                if amount == unset:
                    amount = ''
                t_cmd = ("vrrp %d track %s %s %s"
                         % (vrid, tr_obj, action, amount))
                cmds.append(t_cmd.rstrip())

        cmds = sorted(cmds)

        # Run the command if requested
        if run:
            result = self.configure_interface(name, cmds)
            # And verify the command succeeded
            if result is False:
                return self.error
            return result

        # Otherwise return the formatted command
        return cmds