Issue with speed of API calls

Solved
Jacob1
Conversationalist

Issue with speed of API calls

Trying to set up a script to enable or disable all of the static routes in a network - we are currently in a transitional period where if our MPLS fails, we need to disable (but not delete) the static routes, and then reenable them once the link comes back up.

 

My issue is that it takes FOREVER, i.e. multiple seconds, for each update static route (PUT) to return in my powershell script before the next one proceeds.  

 

I've tried putting the API call into {}'s and using Start-Job, but that makes it do nothing.

 

I am aware of the 5/sec rate limit, if I can even get this to run at 2 or 3/sec I would be happy.

 

It does run and work, it just takes longer than doing it by hand.  Some of the API calls take multiple seconds to return.

 

Here is my scrubbed script below, if anyone can help me out I would really appreciate it.

 

** Updated code to streamline some things I didn't need.  End result is still the same right now though.

*** Added some input validation, no changes to the functional parts of the code.

#below line fixes TLS negotiation failure
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

#insert API Key Below
$APIKey = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
$base = 'https://n158.meraki.com/api/v0'
$url = '/organizations'
$uri = $base + $url

$header = @{
    'X-Cisco-Meraki-API-Key' = "$APIKey"
    'Content-Type' = 'application/json'
}

$Organizations = Invoke-RestMethod -Method Get -Uri $uri -Headers $header

foreach ($Organization in $Organizations) {
    
    $tempstr = $Organization.Name

    Write-Output "Getting List of Networks from Organization $tempstr"
}



$tempstr = $obj.ID

$url = "/organizations/$tempstr/networks"

$uri = $base + $url

Start-Sleep -Milliseconds 200

$networks = Invoke-RestMethod -Method GET -uri $uri -Headers $header


Write-Output "Networks found:"

foreach ( $item in $networks ) {
                 
            Write-Output $item.name
        
    }

$netname = Read-Host -Prompt 'Type the name of the network you wish to enable/disable static routes on'

Write-Output "You have selected network $netname"

#incorrectnet checks for bad network name

$incorrectnet = 1

foreach ( $item in $networks ) {
      if($netname -eq $item.name){
        $selectednet = $item
        $incorrectnet = 0
       }
}

if($incorrectnet -eq 1){
Write-Host $netname "is not a valid network name, please try again"
exit
}


$conditional = 3

$conditional = Read-Host -Prompt "Press 1 to enable all static routes, 2 to disable all static routes"

#outputing choice to console

If ($conditional -eq 1){
Write-Output "Enabling all static routes on $netname"
$enable = 'true'
}
Elseif ($conditional -eq 2){
Write-Output "Disabling all static routes on $netname"
$enable = 'false'
}
Else {Write-Output 'Please try again and select a valid option'
    exit
}


#select network ID of selected network for use in next API call
$netid = $selectednet.id

$url = '/networks/' + $netid
$uri = $base + $url + '/staticRoutes/'

Start-Sleep -Milliseconds 200

$staticroutes = Invoke-RestMethod -Method GET -Uri $uri -Headers $header


foreach ($item in $staticroutes ) {

$body = @{
    "name" = $item.name
    "subnet" = $item.subnet
    "gatewayIp" = $item.gatewayIp
    "enabled" = $enable  
    }

    $jsonbody = ConvertTo-Json -Inputobject $body

    $url = '/networks/' + $netid + '/staticRoutes/' + $item.id
    $uri = $base + $url

#blackhole variable is to prevent restmethod from outputting to console
#Sleep is to limit api calls to 5/sec
Start-Sleep -Milliseconds 200
Write-host "Setting Route" $item.name "to" $enable
$blackhole = Invoke-RestMethod -Method PUT -uri $uri -Headers $header -Body $jsonbody -UseBasicParsing



}

Write-host "Completed!"

 

 

1 Accepted Solution
jdsilva
Kind of a big deal

No, you're correct. My experience is about the same in that it takes a couple seconds per API call. The only way around this we've come up with is multi-threading, but even that isn't a linear gain in speed. If you double the threads it's not a 50% reduction in time. 

View solution in original post

6 Replies 6
jdsilva
Kind of a big deal

No, you're correct. My experience is about the same in that it takes a couple seconds per API call. The only way around this we've come up with is multi-threading, but even that isn't a linear gain in speed. If you double the threads it's not a 50% reduction in time. 

BrechtSchamp
Kind of a big deal

I guess this is something Meraki is still missing, having a configuration versioning system of sorts. With other equipment you'd simply have two config files and switch between them when this occurs. Hell, being able to download a full config would already be nice, seeing as the API is still incomplete.

Jacob1
Conversationalist

I agree, this could be solved very simply with the ability to update multiple static routes via one API call.

PhilipDAth
Kind of a big deal
Kind of a big deal

First I would remove all the compulsory sleep operations you have.  The rest is taking long enough without adding those.

Start-Sleep -Milliseconds 200

 

The next thought on my mind is weather this is static routes on an MX or MS.   If it is on an MX have you considered using route tracking?

https://documentation.meraki.com/MX/Networks_and_Routing/MX_Routing_Behavior#Static_Route_Tracking

PhilipDAth
Kind of a big deal
Kind of a big deal

ps. I gave up on using Powershell for scripting.  One of the issues with it is that when you start powershell running for a one off job (such as a triggered event or task scheduler (for example)) it has to instantiate the whole .Net engine.  This can take a couple of seconds.  If you are trying to run a lot of single fire operations this creates big problems.

 

The .Net instantiation is a really slow process, and inherent in the powershell architecture - so can not be fixed.

 

.Net apps suffer the same issue when you recycle their application pools in IIS.  I have clients with apps where IIS can't process any requests for 5 minutes after a pool recycle.

 

 

You may find moving off to other scripting languages like Python will be your best fix.

Jacob1
Conversationalist

We did originally set these as "while next hop responds" however we ran into inconsistent routing issues when doing it this way.

 

Thanks for your help, and unless I can get my boss to try route tracking again (hopefully something that got fixed in newer firmware) I think I will just have to try and make it at least double threaded.  I have removed the sleep operations from my script which helped quite a bit.

Get notified when there are additional replies to this discussion.