I’m discovering RouterOS scripting.
I often get errors because I’m trying to add something that already exists.
For instance, if I run twice a script that includes the following lines, it would fail the second time.
/interface vlan
add interface=bridge1 name=vlan2 vlan-id=2
How can I solve this ?
Is there anything like “delete ifexists” like in SQL scripts ?
Its better to test to see if vlan is already created, and if not, create it. I was told (by rextended) its better to fix the problem and do not use on-error
/interface vlan
# if exist, delete it
remove [find where interface=bridge1 name=vlan2 vlan-id=2]
# create (again)
add interface=bridge1 name=vlan2 vlan-id=2
If not exist, create it, if exist, delete it before create again, just for fun, is a test:
:global delifexist do={ [:parse (“$1 ; remove [find where $2] ; add $2”)] }
$delifexist “/ip/firewall/mangle” “action=accept chain=prerouting disabled=yes comment=test”
Obviously is only a test for fun, the better way is what Jotne wrote
Of course there is a definite difference between “add vlan2 and ignore the error when it already exists” and “first remove vlan2 if it exists and then add it again”.
This has a totally different effect on the resulting router configuration when vlan2 already existed and had further config attached to it (like IP address, interface list membership, etc).
So which solution you choose totally depends on what requirements you have.
the “delifexist” is just for fun, to test and demostrate the power of routeros scripting,
which obviously could have more power if it were better implemented…
like “time” problem, missing basic functions like replace on string, etc.
Well, a definite improvement would be to have an “ignore minor errors” mode in script execution.
The “on-error” clause acts upon individual blocks so it would have to be applied to every line separately (e.g. using a construct as you showed).
However, in daily practice it is often very inconvenient that one cannot just /import a script and have it go until it encounters a really fatal error.
For example, I sometimes try to transfer config from one router to another using a /export file, and the routers are not completely identical.
E.g. one is a CCR and the other is a CHR I keep as a backup in case the CCR hardware fails.
Or one is a RB2011 and the other is a RB4011 I bought as an upgrade.
The /export files contain minor details the target router does not support, e.g. config for LED, LCD, IP cloud, slightly different SFP interface name, etc.
One has to carefully edit out every config item not supported on the target, or else the whole /import fails (worse: it fails halfway and leaves the router in the half-configured state).
It would be so much more convenient when one could use something like “/import filename ignore-errors=yes” and it would just print the error message (including the line that caused it!) and go on with the next line.
That would also have to be the default for “reset configuration and run script”, where it would also put the error log into some file.
Or there could be a new command “/system script ignore-errors=yes log=file” that you could put on top of such a /import file.
This can be implemented (just for uncomplete example) using a text editor than support RegEx or the replace of “carriage return/new line”, and replacing
\r\n/
with
} on-error={}\r\n:do {/
on the export file before importing it,
or something like that until mikrotik implement the correct way…
Obviously can be writed a script than import the .rsc but is really complex evaluate each line and find and report the errors founded.
I started a project on this but RouterOS/Mikrotik support could not provide me with all supported menu entries for that specific router, so that project it is on hold till that is possible.
Any of the above approaches above can work to re-write an exported config, pick you poison. All have pro/cons:
the issue with “delete then add” approach is you can lose access the router by accident pretty easily (e.g. the time between the add and remove)
wrapping on-error={} around an “add” is simple, but that not going to cause the attribute values to get set again on import if “reseting” attributes was desired
the more complex “IF exists, use ‘set’ ELSE use ‘add’” logic is needed for each line want to override attributes too when using import.
The key thing to know is import and export are NOT really symmetrical. export does represent the config, but in variety of ways. Like whether “sensitive” data is included in the export, which dramatically effect “importability”. While import is basically the same as saying “run script from this file”, and it doesn’t care if the file was from an export – so “import” is more like “run script”, than just a “load config”.
At a more basic level, if your trying to save the config to then import on SAME box, you may be better off just using the /system/backup to save all the config+data. If what you want is to clone a config to another box then use /export on one, and /import after a /system/reset-configuration no-default=yes on the new one works.
It’s the “create-if-missing” option that missing in “set” if you ask me. Otherwise, it just a lot of extra code needed to do same thing, as seen here.
Thank you all for your replies and specifically for this last one !
When I export a config, I often wondered and still wonder what is the specific device state the device needs to be in to cleanly apply the exported data.
If I need to reset the device to blindly apply the exported data, may this data should start with a “reset” statement.
you can not put “reset” inside (re)config file
must be doed separately, waith the reboot, then apply the (new) config line-by-line on terminal for see if something cause error(s)