Use API or REST-API to invoke arbitrary scripting command

Hi All,

Is it possible to run arbitrary script statements with the APIs? For example:

:do { xxx } on-error={ yyy }

or:

foreach item in=[ xxx ] do={ yyy }

Please note, writing the body of the script with:

/system/script/add name=script_name source="script_source"

and running with:

/system/script/run script_name

is not a good option for me because of the high volume of writes expected to be made (flash wear) and the low speed.

Thank you

https://router/rest/execute{“script”:“script_source”}

/execute script="script_source"

trying POST now with this:

.\curl.exe -k -u admin:admin -X POST https://172.20.234.129/rest/execute --data '{"script": "/log/info test"}' -H "content-type:application/json"

and I get the following error:

{"detail":"Invalid JSON","error":400,"message":"Bad Request"}curl: (3) unmatched close brace/bracket in URL position 5:
test}
    ^

am I doing something wrong with whitespace?

also, with API, similarly fails… Below, I try to run a script to add an IP address, it returns " !done ", then I run a simple " /ip/address/print " and only the previously present address is shown…


Socket is open, router responds.
>>> /execute
>>> =script="/ip/address/add interface=ether1 address=10.10.10.10/24"
>>>

<<< !done
<<< =ret=*35

>>> /ip/address/print
>>>

<<< !re
<<< =.id=*9
<<< =address=172.20.234.129/20
<<< =network=172.20.224.0
<<< =interface=ether1
<<< =actual-interface=ether1
<<< =invalid=false
<<< =dynamic=true
<<< =disabled=false

<<< !done

I had success with python using:

import requests
from requests.auth import HTTPBasicAuth
import json
import urllib3
import time

urllib3.disable_warnings()

url = 'https://172.23.138.107/rest'
username = 'admin'
password = 'admin'

for i in range(10):
    
    # time.sleep(0.1)
    response = requests.post(url + '/execute', 
                         auth = HTTPBasicAuth(username, password), 
                         verify = False, 
                         json = {'script': f'log info "post method {"test"*i}"'})
    
    print(
        json.dumps(response.json(), indent=4)
    )

I’m guessing you’re using windows (based on the .\curl.exe …). So the “shell escaping” is different for something like cmd.exe. So you can’t use the single quote to avoid inner escaping, so the --data part should be:

   "{\"script\": \"/log/info test\"}"

Hello,

I would like to leverage the REST API to update containers running on my router but not a big fan of using credentials giving wide access to the device.
Instead, I would like to use a script but I would need to pass arguments (at least the tag of the image).

Is there a way anyone can think of, to pass arguments to a script via a REST API call ?

Thank you

Perhaps you can do is write the entire script(e.g. with container start/stop/whatever) to /system/script via PUT, with argument generated/interpolated as a local variable within that script in the calling code. Use POST on /system/script/run, and finally use DELETE to remove the script with REST

What I’ve done, is write a script to update the containers, based on a json file hosted on Gitea.

The only call that remains is a “script run” which still requires some permissions but I’m satisfied with the current setup.

Thanks (a little bit late) for your answer Amm0.