How to handle invalid elements in the API

KarstenI
Kind of a big deal
Kind of a big deal

How to handle invalid elements in the API

I am still working on my script to copy an SSID between networks and change an SSID. But now I struggle with the implementation of the API.

 

Problem:

I use getNetworkWirelessSsid to read the SSID and write the SSID with updateNetworkWirelessSsid.

But the API call getNetworkWirelessSsid gives me the following result for my test-SSID:

 

{'authMode': '8021x-radius',
 'availabilityTags': [],
 'availableOnAllAps': True,
 'bandSelection': 'Dual band operation',
 'defaultVlanId': 999,
 'dot11r': {'adaptive': False, 'enabled': False},
 'dot11w': {'enabled': True, 'required': True},
 'enabled': True,
 'encryptionMode': 'wpa-eap',
...
 'wpaEncryptionMode': 'WPA2 only'}

 

 

The Schema Definition for updateNetworkWirelessSsid has some restrictions that make this invalid, and I can't write it back. For example, this SSID uses DOT1X authentication, but I get the element "encryptionMode" returned, which is only valid for PSK SSIDs. There are a couple of more restrictions where elements are dependent on each other.

 

How do I handle this (and I will never understand why this invalid element is returned)?

I can only think of having if-conditions where I match each restriction and remove the element if this element is not allowed on this SSID:

 

if source_ssid["authMode"] == '8021x-radius':
    source_ssid.pop('encryptionMode')

 

But this is an extremely dirty workaround, and I need an individual function for each object I want to copy. 

Or is there a "switch" or "parameter" to tell the system to ignore everything that is not valid? At least I didn't find anything like this.

 

Any idea or advice?

 

 

 

10 Replies 10
RaphaelL
Kind of a big deal
Kind of a big deal

You are describing the endpoint that I hate the most. 

 

You do a 'GET' of the SSID settings, you get bunch of nonsense , you try to 'PUT' the same exact data, you get bunch of errors 🙂 fun

KarstenI
Kind of a big deal
Kind of a big deal

Well, although this doesn't help, I am happy to see that I am not alone in my frustration ... 🤣

PhilipDAth
Kind of a big deal
Kind of a big deal

I must be lucky not to have run into this yet using my approach above.  🙂

 

If that happened - you test for the invalids and delete from my kwargs that I build.  Or maybe if I specify kwargs that are not used, they get ignored by updateNetworkWirelessSsid.  I guess they would have to be ignored.

DarrenOC
Kind of a big deal
Kind of a big deal

I applaud the effort and steadfastness @KarstenI but you could have done this manually by now 😉

Darren OConnor | doconnor@resalire.co.uk
https://www.linkedin.com/in/darrenoconnor/

I'm not an employee of Cisco/Meraki. My posts are based on Meraki best practice and what has worked for me in the field.
KarstenI
Kind of a big deal
Kind of a big deal

I think big and not only for the 15 branches where I need it now ... 😉

And I also see it as a preparation for the DEVASC certification that I want to do eventually.

PhilipDAth
Kind of a big deal
Kind of a big deal

Here is the jist of it, using Python, for MR based networks:

 

First grab the settings from the source network:

# Grab the current WiFi settings
ssidSettings=dashboard.wireless.getNetworkWirelessSsid(fromNetworkId,ssidNumber)

Then copy all of the settings to the new network:

# Build the SSID argument list
kwargs = {}
for setting in ssidSettings:
 kwargs[setting]=ssidSettings[setting]

dashboard.wireless.updateNetworkWirelessSsid(toNet['id'],**kwargs)

 

@sungod probably has a better approach ...

RaphaelL
Kind of a big deal
Kind of a big deal

And this is working for you Phil ? I don't have the same luck 😞

 

Recently I can't copy my WPA2-Enterprise SSID settings. When I do the push It pukes couple errors about RadSecTLS timeouts ( which are not visible on the dashboard ). Opened a case , waiting ...

PhilipDAth
Kind of a big deal
Kind of a big deal

Yes, I've used it maybe 10 to 20 times to copy WiFi settings.

sungod
Kind of a big deal

@PhilipDAth 

 

I tend to follow old-school defensive programming practices...

 

There are API calls that return elements with a None value when they really shouldn't, or that change behaviour without notice, or that give the same data with different element names for no apparent reason.

 

Anything I need to rely on, I code to validate each element and then follow the rules to build the parameter list for the write operation. It's more effort, but still a lot easier than paper coding pads and opcode tables.

 

I know if I trust what an API response provides, there is a higher likelihood something will break, probably at 0200 on a Saturday.

 

RaphaelL
Kind of a big deal
Kind of a big deal

My favorite example 🙂 

 

get /networks/{networkId}/wireless/ssids 

{'authMode': '8021x-radius',
 'availabilityTags': [],
 'availableOnAllAps': True,
 'bandSelection': 'Dual band operation',
 'dot11r': {'adaptive': False, 'enabled': True},
 'dot11w': {'enabled': False, 'required': False},
 'enabled': True,
 'encryptionMode': 'wpa-eap',
 'ipAssignmentMode': 'Bridge mode',
 'lanIsolationEnabled': False,
 'mandatoryDhcpEnabled': False,
 'minBitrate': 11,
 'name': 'XXXXXX',
 'number': 0,
 'perClientBandwidthLimitDown': 0,
 'perClientBandwidthLimitUp': 0,
 'perSsidBandwidthLimitDown': 0,
 'perSsidBandwidthLimitUp': 0,
 'radiusAccountingEnabled': True,
 'radiusAccountingInterimInterval': 1200,
 'radiusAccountingServers': [{'caCertificate': None,
                              'host': 'XXXXX',
                              'id': 'XXXXXXX',
                              'openRoamingCertificateId': None,
                              'port': 1813},
                             {'caCertificate': None,
                              'host': 'XXXXXX',
                              'id': 'XXXXXX',
                              'openRoamingCertificateId': None,
                              'port': 1813}],
 'radiusAttributeForGroupPolicies': 'Airespace-ACL-Name',
 'radiusAuthenticationNasId': '$NODE_MAC$:$VAP_NUM$',
 'radiusCalledStationId': '$NODE_MAC$:$VAP_NAME$',
 'radiusCoaEnabled': True,
 'radiusFailoverPolicy': None,
 'radiusFallbackEnabled': False,
 'radiusLoadBalancingPolicy': None,
 'radiusOverride': True,
 'radiusProxyEnabled': False,
 'radiusRadsecTlsIdleTimeout': 900,
 'radiusServerAttemptsLimit': 3,
 'radiusServerTimeout': 1,
 'radiusServers': [{'caCertificate': None,
                    'host': 'XXXX',
                    'id': 'XXXXXX',
                    'openRoamingCertificateId': None,
                    'port': 1812},
                   {'caCertificate': None,
                    'host': 'XXXXXX',
                    'id': 'XXXXX',
                    'openRoamingCertificateId': None,
                    'port': 1812}],
 'radiusTestingEnabled': False,
 'speedBurst': {'enabled': False},
 'splashPage': 'None',
 'ssidAdminAccessible': False,
 'useVlanTagging': False,
 'visible': False,
 'wpaEncryptionMode': 'WPA2 only'}

 you try to push to a new network : 

 

"RADIUS RADSec TLS idle timeout interval must be greater than RADIUS accounting interim interval"

 

remove "radiusRadsecTlsIdleTimeout" ( because where did that come from ? not present on the dashboard . I know 1200 > 900)

you get : 'encryptionMode' must be one of: 'wep' or 'wpa'

 

remove encryptionMod. It works.... 

 

How hard is it to push the same payload that you got.... 

Get notified when there are additional replies to this discussion.