Help with Script to change server NordVPN

Hi everyone :slight_smile:
Could I ask for help with script to change NordVPN server to recommended?
https://nordvpn.com/pl/servers/tools/
I found api instruction:
https://blog.sleeplessbeastie.eu/2019/02/18/how-to-use-public-nordvpn-api/
Mikrotik and NordVpn connected together with this tutorial:
https://wiki.mikrotik.com/wiki/IKEv2_EAP_between_NordVPN_and_RouterOS
Thank You very much for your interest in the topic and help :slight_smile:

The API returns json data, parsing that in RouterOS is not an easy task.
I am interested myself, but as the topic is really complex I did not yet give it a try.

maybe this will help
https://github.com/Winand/mikrotik-json-parser

what do you thing about this script?

:local CurrentNordvpnAddress [/ip ipsec peer get [find name=NordVPN] address];
:local NewNordvpnAddress ([/tool fetch url=("https://api.nordvpn.com/v1/servers/recommendations\?limit=1") output=user as-value ]->"data");
:set NewNordvpnAddress [:pick $NewNordvpnAddress [:find $NewNordvpnAddress "hostname"] [:find $NewNordvpnAddress "\",\"load"]];
:set NewNordvpnAddress [:pick $NewNordvpnAddress 11 29];
:if ($CurrentNordvpnAddress != $NewNordvpnAddress) do={
    /ip ipsec peer set [ find name=NordVPN ] address=$NewNordvpnAddress;
}

v2

:local CurrentNordvpnAddress [/ip ipsec peer get [find name=NordVPN] address];
:local NewNordvpnAddress ([/tool fetch url=("https://api.nordvpn.com/v1/servers/recommendations\?limit=1") output=user as-value ]->"data");
:local Ikev2Nordvpn [:find $NewNordvpnAddress "ikev2"];
:set NewNordvpnAddress [:pick [:pick $NewNordvpnAddress [:find $NewNordvpnAddress "hostname"] [:find $NewNordvpnAddress "\",\"load"]] 11 29];
:if ($Ikev2Nordvpn > 0 && $CurrentNordvpnAddress != $NewNordvpnAddress) do={
    /ip ipsec peer set [ find name=NordVPN ] address=$NewNordvpnAddress;
}

v3

:local CurrentNordvpnAddress [/ip ipsec peer get [find name=NordVPN] address];
:local NewNordvpnAddress ([/tool fetch url=("https://api.nordvpn.com/v1/servers/recommendations\?limit=1") output=user as-value ]->"data");
:local Ikev2Nordvpn [:find $NewNordvpnAddress "ikev2"];
:set NewNordvpnAddress [:pick [:pick $NewNordvpnAddress [:find $NewNordvpnAddress "hostname"] [:find $NewNordvpnAddress "\",\"load"]] 11 29];
:local CurrentNordvpnLoad ([/tool fetch url=("https://api.nordvpn.com/server/stats/$CurrentNordvpnAddress") output=user as-value ]->"data");
:set CurrentNordvpnLoad [:pick [:pick $CurrentNordvpnLoad [:find $CurrentNordvpnLoad "percent\":"] [:find $CurrentNordvpnLoad "}"]] 9 12];
:if ($CurrentNordvpnLoad > 30 && $Ikev2Nordvpn > 0 && $CurrentNordvpnAddress != $NewNordvpnAddress) do={
    /ip ipsec peer set [ find name=NordVPN ] address=$NewNordvpnAddress;
}

v4

:local CurrentNordvpnAddress [/ip ipsec peer get [find name=NordVPN] address];
:local CurrentNordvpnLoad ([/tool fetch url=("https://api.nordvpn.com/server/stats/$CurrentNordvpnAddress") output=user as-value ]->"data");
:set CurrentNordvpnLoad [:pick [:pick $CurrentNordvpnLoad [:find $CurrentNordvpnLoad "percent"] [:find $CurrentNordvpnLoad "}"]] 9 12];
:if ($CurrentNordvpnLoad > 20) do={
    :local NewNordvpnAddress ([/tool fetch url=("https://api.nordvpn.com/v1/servers/recommendations\?limit=1") output=user as-value ]->"data");
    :local Ikev2Nordvpn [:find $NewNordvpnAddress "ikev2"];
    :set NewNordvpnAddress [:pick [:pick $NewNordvpnAddress [:find $NewNordvpnAddress "hostname"] [:find $NewNordvpnAddress "\",\"load"]] 11 29];
    :if ($Ikev2Nordvpn > 0 && $CurrentNordvpnAddress != $NewNordvpnAddress) do={
        /ip ipsec peer set [ find name=NordVPN ] address=$NewNordvpnAddress;
    }
}

v5

####DESCRIPTION####
#https://api.nordvpn.com/v1/servers/countries
#:local ApiNordvpnCountry 195;
#https://api.nordvpn.com/v1/servers/groups
#:local ApiNordvpnGroup 25;
#MaxLoad is usded to check the actual server load, if the load go over the MaxLoad, the script will change the vpn server
#:local ApiNordvpnMaxLoad 20;

####CONFIG####
:local ApiNordvpnCountry;
:local ApiNordvpnGroup;
:local ApiNordvpnMaxLoad 20;

####SCRIPT####
:local CurrentNordvpnAddress [/ip ipsec peer get [find name=NordVPN] address];
:local CurrentNordvpnLoad ([/tool fetch url=("https://api.nordvpn.com/server/stats/$CurrentNordvpnAddress") output=user as-value ]->"data");
:set CurrentNordvpnLoad [:pick [:pick $CurrentNordvpnLoad [:find $CurrentNordvpnLoad "percent"] [:find $CurrentNordvpnLoad "}"]] 9 99];
:if ($CurrentNordvpnLoad > $ApiNordvpnMaxLoad) do={
    :local NewNordvpnAddress ([/tool fetch url=("https://api.nordvpn.com/v1/servers/recommendations\?filters[servers_groups]=$ApiNordvpnGroup&filters[servers_technologies][identifier]=ikev2&filters[country_id]=$ApiNordvpnCountry&limit=1") output=user as-value ]->"data");
    :set NewNordvpnAddress [:pick [:pick $NewNordvpnAddress [:find $NewNordvpnAddress "hostname"] [:find $NewNordvpnAddress "\",\"load"]] 11 99];
    :if ($CurrentNordvpnAddress != $NewNordvpnAddress) do={
        /ip ipsec peer set [ find name=NordVPN ] address=$NewNordvpnAddress;
    }
}

v6

####DESCRIPTION####
#ApiNordvpnCountry is used to select a country, if it is empty then the country will be selected automatically
#:local ApiNordvpnCountry 195;
#https://api.nordvpn.com/v1/servers/countries
#ApiNordvpnGroup is used to select server type, if it is empty then will be selected automatically
#:local ApiNordvpnGroup 25;
#https://api.nordvpn.com/v1/servers/groups
#ApiNordvpnMaxLoad is used to define the maximum acceptable load of the current server, after exceeding this value the server will be changed
#:local ApiNordvpnMaxLoad 20;

####CONFIG####
:local ApiNordvpnCountry;
:local ApiNordvpnGroup 15;
:local ApiNordvpnMaxLoad 20;

####SCRIPT####
:local CurrentNordvpnAddress [/ip ipsec peer get [find name=NordVPN] address];
:local CurrentNordvpnLoad ([/tool fetch url=("https://api.nordvpn.com/server/stats/$CurrentNordvpnAddress") output=user as-value ]->"data");
:set CurrentNordvpnLoad [:pick [:pick $CurrentNordvpnLoad [:find $CurrentNordvpnLoad "percent"] [:find $CurrentNordvpnLoad "}"]] 9 99];
:if ($CurrentNordvpnLoad > $ApiNordvpnMaxLoad) do={
	:local NewNordvpnAddress ([/tool fetch url=("https://api.nordvpn.com/v1/servers/recommendations\?filters[servers_groups]=$ApiNordvpnGroup&filters[country_id]=$ApiNordvpnCountry&filters[servers_technologies][identifier]=ikev2&limit=1") output=user as-value ]->"data");
	:set NewNordvpnAddress [:pick [:pick $NewNordvpnAddress [:find $NewNordvpnAddress "hostname"] [:find $NewNordvpnAddress "\",\"load"]] 11 99];
	:if ([:len $NewNordvpnAddress] = 0) do={
		:log info "NordVPN: no server found for the current configuration";
	} else={
		:if ($CurrentNordvpnAddress != $NewNordvpnAddress) do={
		/ip ipsec peer set [ find name=NordVPN ] address=$NewNordvpnAddress;
		}
	}
}

You do not need to end every line witch ;.
Its only needed when you have several commands on same line.

thank you for your comments, does it look better now? :slight_smile:

####DESCRIPTION####
#ApiNordvpnCountry is used to select a country, if it is empty then the country will be selected automatically
#:local ApiNordvpnCountry 195
#https://api.nordvpn.com/v1/servers/countries
#ApiNordvpnGroup is used to select server type, if it is empty then will be selected automatically
#:local ApiNordvpnGroup 25
#https://api.nordvpn.com/v1/servers/groups
#ApiNordvpnMaxLoad is used to define the maximum acceptable load of the current server, after exceeding this value the server will be changed
#:local ApiNordvpnMaxLoad 20

####CONFIG####
:local ApiNordvpnCountry
:local ApiNordvpnGroup 15
:local ApiNordvpnMaxLoad 20

####SCRIPT####
:if (([:typeof $ApiNordvpnCountry] = "num" || [:len $ApiNordvpnCountry] = 0) && ([:typeof $ApiNordvpnGroup] = "num" || [:len $ApiNordvpnGroup] = 0) && ([:typeof $ApiNordvpnMaxLoad] = "num" || [:len $ApiNordvpnMaxLoad] = 0)) do={
	:local CurrentNordvpnAddress [/ip ipsec peer get [find name=NordVPN] address]
	:local CurrentNordvpnLoad ([/tool fetch url=("https://api.nordvpn.com/server/stats/$CurrentNordvpnAddress") output=user as-value ]->"data")
	:set CurrentNordvpnLoad [:pick [:pick $CurrentNordvpnLoad [:find $CurrentNordvpnLoad "percent"] [:find $CurrentNordvpnLoad "}"]] 9 99]
	:if ($CurrentNordvpnLoad > $ApiNordvpnMaxLoad) do={
		:local NewNordvpnAddress ([/tool fetch url=("https://api.nordvpn.com/v1/servers/recommendations\?filters[servers_groups]=$ApiNordvpnGroup&filters[country_id]=$ApiNordvpnCountry&filters[servers_technologies][identifier]=ikev2&limit=1") output=user as-value ]->"data")
		:if ($NewNordvpnAddress = "[]") do={
			:log info "NordVPN: server not found for the current configuration"
		} else={
			:local NewNordvpnLoad [:pick [:pick $NewNordvpnAddress [:find $NewNordvpnAddress "nordvpn.com"] [:find $NewNordvpnAddress ",\"status"]] 20 99]
				:if ($CurrentNordvpnLoad > $NewNordvpnLoad) do={
					:set NewNordvpnAddress [:pick [:pick $NewNordvpnAddress [:find $NewNordvpnAddress "hostname"] [:find $NewNordvpnAddress "\",\"load"]] 11 99]
					:if ($CurrentNordvpnAddress != $NewNordvpnAddress) do={
						/ip ipsec peer set [ find name=NordVPN ] address=$NewNordvpnAddress
					}
				}
		}
	}
} else={
	:log info "NordVPN: error! variables must be numbers!"
}

v8

####DESCRIPTION####
#ApiNordvpnCountry is used to select a country, if it is empty then the country will be selected automatically
#:local ApiNordvpnCountry 195
#https://api.nordvpn.com/v1/servers/countries
#ApiNordvpnGroup is used to select server type, if it is empty then will be selected automatically
#:local ApiNordvpnGroup 25
#https://api.nordvpn.com/v1/servers/groups
#ApiNordvpnMaxLoad is used to define the maximum acceptable load of the current server, after exceeding this value the server will be changed
#:local ApiNordvpnMaxLoad 40

####CONFIG####
:local ApiNordvpnCountry
:local ApiNordvpnGroup 15
:local ApiNordvpnMaxLoad 20

####SCRIPT####
:if (([:typeof $ApiNordvpnCountry] = "num" || [:len $ApiNordvpnCountry] = 0) && ([:typeof $ApiNordvpnGroup] = "num" || [:len $ApiNordvpnGroup] = 0) && ([:typeof $ApiNordvpnMaxLoad] = "num" || [:len $ApiNordvpnMaxLoad] = 0)) do={
	:local CurrentNordvpnAddress [/ip ipsec peer get [find name=NordVPN] address]
	:local CurrentNordvpnLoad ([/tool fetch url=("https://api.nordvpn.com/server/stats/$CurrentNordvpnAddress") output=user as-value ]->"data")
	:set CurrentNordvpnLoad [:pick [:pick $CurrentNordvpnLoad [:find $CurrentNordvpnLoad "percent"] [:find $CurrentNordvpnLoad "}"]] 9 99]
	:if ($CurrentNordvpnLoad > $ApiNordvpnMaxLoad) do={
		:local NewNordvpnAddress ([/tool fetch url=("https://api.nordvpn.com/v1/servers/recommendations\?filters[servers_groups]=$ApiNordvpnGroup&filters[country_id]=$ApiNordvpnCountry&filters[servers_technologies][identifier]=ikev2&limit=1") output=user as-value ]->"data")
		:if ($NewNordvpnAddress = "[]") do={
			:log info "NordVPN: server not found for the current configuration"
		} else={
			:local NewNordvpnLoad [:pick [:pick $NewNordvpnAddress [:find $NewNordvpnAddress "nordvpn.com"] [:find $NewNordvpnAddress ",\"status"]] 20 99]
			:set NewNordvpnAddress [:pick [:pick $NewNordvpnAddress [:find $NewNordvpnAddress "hostname"] [:find $NewNordvpnAddress "\",\"load"]] 11 99]
			:if (($CurrentNordvpnAddress != $NewNordvpnAddress) && ($CurrentNordvpnLoad > $NewNordvpnLoad)) do={
				/ip ipsec peer set [ find name=NordVPN ] address=$NewNordvpnAddress
			}
		}
	}
} else={
	:log info "NordVPN: error! variables must be numbers!"
}

i need hep
i have variables for example:

ch-nl2.nordvpn.com
de655.nordvpn.com
pl85.nordvpn.com

I would like to receive such results:

ch-nl
de
pl

do you have any idea how to do this?

It does not look like the :find command support regex, just string match.

So this does not work:

:put [:find $"ch-nl2.nordvpn.com" "[0-9]"]

It then makes it hard to find on the string where an unknown number starts.
You can loop trough and test number by number from 0-9, but its ugly.

find	   :find <arg> <arg> <start>	return position of substring or array element	:put [:find "abc" "a" -1];

This give your output, but its ugly

{
:local info "ch-nl2.nordvpn.com"
:local pos
:for i from=0 to=9 do={
	:local test [:find $info $i]
	:if ([:typeof $test]="num") do={set $pos $test}
	}
:put [:pic $info 0 $pos] 
}
ch-nl