def removeentry(self, branch, find=''): """Removes entries from remote host based onto <find>. If <find> is note set, it will remove everything under that <branch>. That method compares the configuration before and after command execution to detect changes and form the bool result. :param branch: (str) Branch of commands. :param find: (str) Mikrotik CLI filter. :return: (bool) True when <propvals> have changed the configuration. If for some reason, configuration remains unchanged False will be returned, but the <self.errc> will be zero. It will also return False in case of error. """ if not hasstring(branch): return self.err(1) branch = branchfix(branch) if not haskey(self.branch, branch, dict): return self.err(2, branch) if self.branch[branch]['class'] != 'list': return False if self.branch[branch]['readonly']: return False if not hasstring(find): find = '' # Count entries before remove command command = ':put [:len [{} find]]'.format(branch) entries_c0 = self.command(command) if not entries_c0: return self.err(3) # Remove command command = '{} remove [find {}]'.format(branch, find) results = self.command(command, hasstdout=False) if results: return self.err(4, results) # Count entries after remove command command = ':put [:len [{} find]]'.format(branch) entries_c1 = self.command(command) if not entries_c1: return self.err(5) # Compare Before and After remove command if entries_c0 != entries_c1: return True # Changed return False # Not changed != Failed
def getinfo_interfaces(self, interface=None): """Meta method. Retrieves information from Router. """ branch = '/interface' properties = ['name', 'type', 'mac-address'] results1 = self.getvalues(branch, properties, find='dynamic!=yes', iid=True) branch = '/ip address' properties = ['address', 'interface'] results2 = self.getvalues(branch, properties) results = {} if results1: for result1 in results1: name = None if haskey(result1, 'name'): name = result1['name'] if not hasstring(name): continue results[name] = { '.id': result1['.id'], 'type': result1['type'], 'mac_address': result1['mac-address'], 'ip_address': [] } # Bug: PPPoE intrfaces from ISP will have irregular network # address if results2: for result2 in results2: if result2['interface'] == name: address = result2['address'].split('/') network = ipaddress.IPv4Network(result2[ 'address'].decode('utf-8'), False) ip_address = { 'address': address[0], 'nbits': address[1], 'netmask': str( network.netmask).encode('utf-8'), 'network': str( network.network_address).encode('utf-8'), 'broadcast': str( network.broadcast_address).encode('utf-8') } results[name]['ip_address'].append(ip_address) return results
def propvals_diff_getvalues(propvals, getvalues): """Compares two different sets of properties and values. :param propvals: (dict) 1st set. :param getvalues: (dict) 2nd set. :return: (bool) True if they are same, False if not. """ if not hasdict(propvals): return None if not haslist(getvalues): return True for prop in propvals: for getvalue in getvalues: if haskey(getvalue, prop): if propvals[prop] != getvalue[prop]: return True else: return True return False
def test_haskey(self): """Test if key exists in dictionary. """ none0 = None int0 = 0 int1 = 1 int2 = -1 str0 = '' str1 = 'abcd' list0 = [] list1 = ['ab', 'cd'] dict0 = {} dict1 = {'ab': 'cd'} set0 = set() set1 = set(['a', 'b', 1, 2]) tuple0 = () tuple1 = ('a', 'b', 1, 2) self.assertFalse(valid.haskey(none0, none0)) self.assertFalse(valid.haskey(dict1, none0)) self.assertFalse(valid.haskey(dict1, int0)) self.assertFalse(valid.haskey(dict1, int1)) self.assertFalse(valid.haskey(dict1, int2)) self.assertFalse(valid.haskey(dict1, str0)) self.assertFalse(valid.haskey(dict1, str1)) self.assertFalse(valid.haskey(dict1, list0)) self.assertFalse(valid.haskey(dict1, list1)) self.assertFalse(valid.haskey(dict1, dict0)) self.assertFalse(valid.haskey(dict1, dict1)) self.assertFalse(valid.haskey(dict1, set0)) self.assertFalse(valid.haskey(dict1, set1)) self.assertFalse(valid.haskey(dict1, tuple0)) self.assertFalse(valid.haskey(dict1, tuple1)) key0 = 'ab' self.assertTrue(valid.haskey(dict1, key0, str)) # assertTrue self.assertFalse(valid.haskey(dict1, key0, list)) # assertFalse
def addentry(self, branch, propvals=''): """Adds new entries to remote host. That method compares the configuration before and after command execution to detect changes and form the bool result. :param branch: (str) Branch of commands :param propvals: (str) Space seperated pairs of Variable=Value :return: (bool) True when <propvals> have changed the configuration. If for some reason, configuration remains unchanged False will be returned, but the <self.errc> will be zero. It will also return False in case of error. """ if not hasstring(branch): return self.err(1) branch = branchfix(branch) if not haskey(self.branch, branch, dict): return self.err(2, branch) if self.branch[branch]['class'] != 'list': return False if self.branch[branch]['readonly']: return False if not hasstring(propvals): return self.err(3) # Count entries before add command command = ':put [:len [{} find]]'.format(branch) entries_c0 = self.command(command) if not entries_c0: return self.err(4) # Check if such an entry exists if self.branch[branch]['id']: propvals_d = propvals_to_dict(propvals) prop = self.branch[branch]['id'][0] if haskey(propvals_d, prop): command = ':put [:len [{} find {}={}]]'.format(branch, prop, propvals_d[prop]) result = self.command(command) if result[0] != '0': return False # Add Command command = '{} add {}'.format(branch, propvals) results = self.command(command, hasstdout=False) if results: if self.checkline_falsepos(results[0]): self.err0() return False # Not changed != Failed self.err(5, command) return self.err(6, results) # Count entries after add command command = ':put [:len [{} find]]'.format(branch) entries_c1 = self.command(command) if not entries_c1: return self.err(7) # Compare Before and After add command if entries_c0 != entries_c1: return True # Changed return False # Not changed != Failed
def setvalues(self, branch, propvals='', find=''): """Sets requested values to remote host. That method compares the configuration before and after command execution to detect changes and form the bool result. :param branch: (str) Branch of commands. :param propvals: (dict) Dictionary of Variables=Values. :param find: (str) Mikrotik CLI filter. :return: (bool) True when <propvals> have changed the configuration. If for some reason, configuration remains unchanged False will be returned, but the <self.errc> will be zero. It will also return False in case of error. """ if not hasstring(branch): return self.err(1) branch = branchfix(branch) if not haskey(self.branch, branch, dict): return self.err(2, branch) if self.branch[branch]['readonly']: return False if not hasstring(propvals): return self.err(3) # Parse propvals to properties propvals_d = propvals_to_dict(propvals) if not hasdict(propvals_d): return self.err(4) properties = [] for prop in propvals_d: properties.append(prop) # Create the find command, if find exists find_command = '' iid = True if self.branch[branch]['class'] == 'list': if hasstring(find): if find.find('=') > 1: find_command = '[find {}] '.format(find) else: iid = False find_command = find + ' ' # Get values before updates getvalues0 = self.getvalues(branch, properties, find, False, iid) if not getvalues0: return self.err(5) # Exit if Get is same as update if not propvals_diff_getvalues(propvals_d, getvalues0): return False # There are no changes to apply # Update command command = '{} set {}{}'.format(branch, find_command, propvals) results = self.command(command, hasstdout=False) if results: self.err(6, command) return self.err(7, results) # Get values after update getvalues1 = self.getvalues(branch, properties, find, False, iid) if not getvalues1: return self.err(8) # Compare Before and After update command if getvalues0 != getvalues1: return True # Changed return False # Not changed != Failed
def getvalues(self, branch, properties, find='', csvout=False, iid=False): """Retrieves requested values from remote host. :param branch: (str) Branch of commands. :param properties: (str / list) List or Comma / Space separated properties. :param find: (str) Mikrotik CLI filter. :param csvout: (bool) Output in CSV File. :param iid: (bool) Adds $id to output. :return: (list) CSV formatted output. Example output if <csvout=True>: Return of <self.command>: [ "value1,value2,value3,...", "value1,value2,value3,...", ... ] Example output if <csvout=False>: Return of <csv_to_list_dict>: [ { results"variable1": "value1", ... } ... ] """ results = [] if not hasstring(branch): self.err(1) return None branch = branchfix(branch) if not haskey(self.branch, branch, dict): self.err(2, branch) return None properties = properties_to_list(properties) if not haslist(properties): self.err(3) return None command = '' commands = [] if (self.branch[branch]['class'] == 'settings' or (self.branch[branch]['class'] == 'list' and find and find.find('=') < 1)): for prop in properties: commands.append('[{} get {} {}]'.format(branch, find, prop)) command = ':put ({})'.format('.",".'.join(commands)) elif self.branch[branch]['class'] == 'list': if iid: commands.append('$i') for prop in properties: commands.append('[{} get $i {}]'.format(branch, prop)) command = (':foreach i in=[' + branch + ' find ' + find + '] ' 'do={:put (' + '.",".'.join(commands) + ')}') else: self.err(4, branch) return None lines = self.command(command) if not lines or self.errc(): self.err(5, command) return None if csvout: results = lines else: results = csv_to_listdict(properties, lines, self.branch[branch], iid) return results