Page 1 of 1

Stop script from failing if packages aren't installed?

Posted: Thu Mar 11, 2010 2:09 pm
by NAB
Hi all,

Consider the following example script:
:if ([/system package find name=wireless disabled=no] = "") do={
    :log info "Wireless package is not installed.";
} else={
    /interface wireless security-profiles add \
    authentication-types=wpa-psk,wpa2-psk,wpa-eap,wpa2-eap \
	eap-methods=passthrough group-ciphers=tkip,aes-ccm group-key-update=5m \
    interim-update=0s mode=dynamic-keys name=DELETEME \
	unicast-ciphers=tkip,aes-ccm \
	wpa-pre-shared-key="XXXXXXXXXX" wpa2-pre-shared-key="XXXXXXXXXX";
	/interface wireless security-profiles remove [find name="DELETEME"];
}
It checks that the wireless package is installed and enabled and, if not, it should log an info message. If the package is installed and enabled, it creates a security profile and then deletes it again.

When the script is run, if the wireless package is installed and enabled, it works perfectly - the profile is added and then deleted correctly.

If the wireless package is not installed or is disabled, the script will not run:
Opening script file wifitest.rsc
Script file loaded successfullyexpected end of command (line 10 column 63)
It looks to me like the script is being parsed before it is being executed and is failing because the '/interface wireless' commands are not valid.
Given that I explicitly check that the package is installed and enabled and DO NOT run that code if it is not, it is rather annoying to have the script fail.

The only way around this I can see is to do something like:
:if ([/system package find name=wireless disabled=no] = "") do={
    :log info "Wireless package is not installed.";
} else={
    /system script add name=TEMPWIFI policy=ftp,reboot,read,write,policy,test,winbox,sniff source="\r\
    \n/interface wireless security-profiles add \\\r\
    \nauthentication-types=wpa-psk,wpa2-psk,wpa-eap,wpa2-eap \\\r\
    \neap-methods=passthrough group-ciphers=tkip,aes-ccm group-key-update=5m \
    \\\r\
    \ninterim-update=0s mode=dynamic-keys name=DELETEME \\\r\
    \nunicast-ciphers=tkip,aes-ccm \\\r\
    \nwpa-pre-shared-key=\"XXXXXXXXXX\" wpa2-pre-shared-key=\"XXXXXXXXXX\";\r\
    \n/interface wireless security-profiles remove [find name=\"DELETEME\"];\r\
    \n"
	/system script run TEMPWIFI;
	/system script remove TEMPWIFI;
}
Which is a horrible botch way of doing things.....

Any ideas anybody?

Re: Stop script from failing if packages aren't installed?

Posted: Thu Mar 11, 2010 3:22 pm
by SurferTim
:if ([/system package find name=wireless disabled=no] = "")
It may be this evaluation. I don't think it is doing it correctly. Maybe try this:
:if (:len [/system package find name=wireless disabled=no] < 1)

Re: Stop script from failing if packages aren't installed?

Posted: Thu Mar 11, 2010 4:05 pm
by janisk
{:local emptyarr; 
:set emptyarr value=[:toarray ""]    
if ([/system package find where name="wireless"] = emptyarr ) do={:put "is"} else={:put "isnot"}
}
if package does not exist, it returns empty array. either compare it to something you know to what you are comparing.
edit:
from my experience in scripting, better check what you you are comparing to what, or else different weird results appear :)

Re: Stop script from failing if packages aren't installed?

Posted: Thu Mar 11, 2010 4:15 pm
by SurferTim
The ":len" command is simpler. It returns the number of elements in the array. It will return zero if the wireless package is not installed or disabled.

Re: Stop script from failing if packages aren't installed?

Posted: Thu Mar 11, 2010 4:19 pm
by janisk
correct, it is simpler if you know that you get empty array in return, but if you don't...

Re: Stop script from failing if packages aren't installed?

Posted: Thu Mar 11, 2010 4:25 pm
by SurferTim
correct, it is simpler if you know that you get empty array in return, but if you don't...
...if you don't, then it should do the "else". That means the wireless package is installed and enabled.

Re: Stop script from failing if packages aren't installed?

Posted: Thu Mar 11, 2010 5:41 pm
by missinlnk
correct, it is simpler if you know that you get empty array in return, but if you don't...
...if you don't, then it should do the "else". That means the wireless package is installed and enabled.
I think janisk is trying to say that he prefers as a programming practice to compare an empty array to the test array, rather than try to compare the length of the array. That way you can guarantee that you're comparing apples to apples and don't run into some kind of weird unanticipated bug further down the road.

Re: Stop script from failing if packages aren't installed?

Posted: Thu Mar 11, 2010 5:45 pm
by SurferTim
correct, it is simpler if you know that you get empty array in return, but if you don't...
...if you don't, then it should do the "else". That means the wireless package is installed and enabled.
I think janisk is trying to say that he prefers as a programming practice to compare an empty array to the test array, rather than try to compare the length of the array. That way you can guarantee that you're comparing apples to apples and don't run into some kind of weird unanticipated bug further down the road.
Bugs are MikroTik's challenge. I use standard programming practices. I am not new at this.

Re: Stop script from failing if packages aren't installed?

Posted: Fri Mar 12, 2010 1:53 am
by NAB
I think you're all missing my point.

The check that I do for the package works perfectly well - if "" is returned, then the package isn't installed or is installed but is not enabled.

The problem is that if the script contains any commands which are implemented within a package which is not installed, then the script doesn't run.

Perhaps if I used pseudo-code it may help. The following script refuses to run if the wireless package is not installed or is disabled:
If wireless package not installed or not enabled then
  print "You will never ever see this message."
else
  Make some change to the wireless configuration
endif
The fact that there is a command in the script which uses a wireless command means that the script WILL NOT RUN (i.e. an error is generated) if the wireless package is not installed and enabled.

Re: Stop script from failing if packages aren't installed?

Posted: Fri Mar 12, 2010 1:58 am
by NAB
I should add that the following script works exactly as expected:
:if ([/system package find name=wireless disabled=no] = "") do={
    :put "No wireless";
} else={
    :put "Wireless installed";
}
It is only the inclusion of commands which are implemented in a package which is not installed which causes the script not to run.

Re: Stop script from failing if packages aren't installed?

Posted: Fri Mar 12, 2010 4:06 am
by dssmiktik
NAB,

Thank you for pointing this out. I haven't run into an issue with it, but now at least I know the knowledge in case I do.

You could use the ':execute' command to execute a command. This doesn't appear to get parsed in a script, thus no errors.
Example:
# returns error and halts script
/invalidcmd

# executes the command, but does not halt script on error
:execute "/invalidcmd"

# executes the command, and gets a return code
:execute ":global ret -1; :set ret [/invalidcmd]"
:global $ret
:if ($ret = -1) do={
   # error with the executed command
} else={
   # $ret now equals returned value of executed command
}
Hope this helps. It tested it on v3.20, v3.30, v4.5, v4.6 so it should be compatible across multiple versions.

Re: Stop script from failing if packages aren't installed?

Posted: Fri Mar 12, 2010 12:56 pm
by SurferTim
I tried several tests with a similar script. I can load the script with bad commands and as long as the evaluation avoids that set, they are not checked. This runs fine as long as the wireless package is disabled. It checks for syntax in all of it , so if you forget a semicolon at the end of the bad command, it fails. But it does not check for valid commands in the unused section.
:if ([/system package find name=wireless disabled=no] = "") do={
    :log info "Wireless package is not installed.";
} else={
    /system bad;
    :bad command test;
    :another bad command;
}

Re: Stop script from failing if packages aren't installed?

Posted: Fri Mar 12, 2010 1:36 pm
by dssmiktik
Have you tried my example from above? It should work as expected.

Re: Stop script from failing if packages aren't installed?

Posted: Fri Mar 12, 2010 11:10 pm
by NAB
OK. This is strange....

The following script works perfectly whether the wireless package is or is not loaded:
:if ([/system package find name=wireless disabled=no] = "") do={
    :log info "Wireless package is not installed.";
} else={
   /interface wireless security-profiles add \
    authentication-types=wpa-psk,wpa2-psk,wpa-eap,wpa2-eap eap-methods=\
    passthrough group-ciphers=tkip,aes-ccm group-key-update=5m \
    interim-update=0s mode=dynamic-keys name=autoconfig \
	unicast-ciphers=tkip,aes-ccm \
	wpa-pre-shared-key="XXXXXXXX" wpa2-pre-shared-key="XXXXXXXX"
}
and the following script crashes if the wireless package is not loaded (and works perfectly if it is):
:if ([/system package find name=wireless disabled=no] = "") do={
    :log info "Wireless package is not installed.";
} else={
   /interface wireless security-profiles remove [find name="XXXX"];
}
So the problem appears to be with only certain lines - in this case, I suspect the '[]' structure, but I don't know why!

Re: Stop script from failing if packages aren't installed?

Posted: Sat Mar 13, 2010 1:34 am
by dssmiktik
Interesting....

After some testing I'm finding these results:
I tested this on v4.6

I'm setting var=0, then comparing it to 1. This should simulate your wireless package 'not installed' test condition.
Each /badcmd command was executed separately inside the ':if () do={}' condition.
:local var 0
:if ($var = 1) do={
   /badcmd property=1           # no error
   /badcmd find property=1     # no error
   /badcmd [find] property=1   # no error
   /badcmd [find property=1]   # Error

   /badcmd \
   find property=1                  # no error

   /badcmd
   find property=1                  # Error

   /badcmd set property=1       # no error
   /badcmd [set] property=1     # no error
   /badcmd [set property=1]     # Error

   /badcmd \
   set property=1                    # no error

   /badcmd
   set property=1                    # Error
}
This may shed some light on how script parsing is done before execution.

Maybe something to do with switching to a sub-menu, then executing the command in '[]' or on a separate line.

Re: Stop script from failing if packages aren't installed?

Posted: Sat Mar 13, 2010 1:31 pm
by SurferTim
How is it crashing? (add: now that the code does just the remove instruction.) Is there an error message displayed? Bad command or a syntax error? I checked the double quotes and the brackets. Neither caused any problems here.

ADD: I tried dssmiktik's test on V3.30. The "[set property=1]" is apparently evaluated and crashes, even in the unused section.