socialwifi / RouterOS-api

Python API to RouterBoard devices produced by MikroTik.
MIT License
251 stars 100 forks source link

how to pass single command argument without key/value (monitor-traffic) #85

Closed danielh-embicon closed 1 year ago

danielh-embicon commented 1 year ago

I'm trying to monitor the traffic of some ethernet ports on my routerboard. In the winbox terminal I can do this by entering this command /interface monitor-traffic ether1 once

I've done a lot of tests trying to "call" this query from the RouterOS-api. My test current test code looks like this:

res = api.get_resource('/interface/')
ans = res.call('monitor-traffic', {'ether1': '', 'once': ''})

However, this throws an "unknown parameter" error: routeros_api.exceptions.RouterOsApiCommunicationError: ('Error "unknown parameter" executing command b\'/interface/monitor-traffic =ether1= =once= .tag=4\'', b'unknown parameter')

I did some diggin in the source code of this API and found the raw representation of the query being sent to my routerboard: [b'/interface/monitor-traffic', b'=ether1=', b'=once=', b'.tag=4']

Out of curiosity I removed the "=" before and after "ether1" by adding a few lines to the send_command method in the ApiCommunicatorBase. This actually gave me a successful response of what I wanted:

Query: [b'/interface/monitor-traffic', b'ether1', b'=once=', b'.tag=4'] Response: [{'rx-packets-per-second': '30', 'rx-bits-per-second': '18776', 'fp-rx-packets-per-second': '36', 'fp-rx-bits-per-second': '22672', 'rx-drops-per-second': '0', 'rx-errors-per-second': '0', 'tx-packets-per-second': '26', 'tx-bits-per-second': '184608', 'fp-tx-packets-per-second': '36', 'fp-tx-bits-per-second': '22672', 'tx-drops-per-second': '0', 'tx-queue-drops-per-second': '0', 'tx-errors-per-second': '0'}]

Now, is there a way I could send my monitor-traffic query using this API without having to modify the source code?

danielh-embicon commented 1 year ago

Here's my quick workaround:

File: base.py, Class: ApiCommunicatorBase, Method: send_command.

def send_command(self, command):
    cm = command.get_api_format()
    for i in range(len(cm)):
        if b'??' in cm[i]:
            cm[i] = cm[i].replace(b'??', b'').strip(b'=')
    # self.base.send_sentence(command.get_api_format())
    self.base.send_sentence(cm)

I can now successfully run my query by adding '??' to the parameter I want to trim '=' from.

res = api.get_resource('/interface/')
ans = res.call('monitor-traffic', {'??ether1': '', 'once': ''})
danielh-embicon commented 1 year ago

Looks like I jumped the gun. The query gives a successfull response no matter what I give it.. ans = res.call('monitor-traffic', {'qwerty': '', 'once': ''})

danielh-embicon commented 1 year ago

Solved.

There's this key called "interface" where the value is supposed to be "ether1".

res = api.get_resource('/interface/')
ans = res.call('monitor-traffic', {'interface': 'ether1', 'once': ''})