Update DHCP nameserver using API

Solved
Dan_s_97
Conversationalist

Update DHCP nameserver using API

We have been trying to update the name server for VLANs using Python through the API but have been getting errors or issues 

 

We can update using the GUI without issue but the idea is to do this in mass (we cannot use templates) 

 

the setting is under Security & SD WAN  > Configure > DHCP

Dan_s_97_1-1765368976926.png

 



our first attempt looks like this 


import meraki
from getpass import getpass

TARGET_NETWORK_NAME = "INSET NAME HERE "
VLANS_TO_UPDATE = [10, 11]
NEW_DNS = "1.1.1.1,8.8.8.8"

def main():
    API_KEY = getpass("Enter your Meraki API Key: ").strip()
    dashboard = meraki.DashboardAPI(api_key=API_KEY, print_console=False)

    org_id = dashboard.organizations.getOrganizations()[0]["id"]

    networks = dashboard.organizations.getOrganizationNetworks(
        org_id, total_pages='all'
    )

    net = next((n for n in networks if n["name"] == TARGET_NETWORK_NAME), None)
    if not net:
        print("Network not found")
        return

    net_id = net["id"]

    for vlan_id in VLANS_TO_UPDATE:
        print(f"\nReading VLAN {vlan_id}...")
        vlan = dashboard.appliance.getNetworkApplianceVlan(net_id, vlan_id)
        print("Current DNS:", vlan.get("dnsNameservers"))

    confirm = input("\nProceed with DNS update? (yes/no): ").lower()
    if confirm not in ("yes", "y"):
        return

    for vlan_id in VLANS_TO_UPDATE:
        print(f"\nUpdating VLAN {vlan_id}...")

        # MUST include required fields
        vlan = dashboard.appliance.getNetworkApplianceVlan(net_id, vlan_id)

        payload = {
            "name": vlan["name"],
            "subnet": vlan["subnet"],
            "applianceIp": vlan["applianceIp"],
            "dhcpHandling": vlan["dhcpHandling"],
            "dhcpLeaseTime": vlan["dhcpLeaseTime"],
            "dhcpBootOptionsEnabled": vlan["dhcpBootOptionsEnabled"],
            "dhcpOptions": vlan["dhcpOptions"],
            "dnsNameservers": NEW_DNS,  # legacy format uses this field
        }

        print("Payload:", payload)

        try:
            dashboard.appliance.updateNetworkApplianceVlan(
                net_id,
                vlan_id,
                **payload
            )
            print(f"Updated VLAN {vlan_id}")
        except Exception as e:
            print(f"Update failed for VLAN {vlan_id}: {e}")

if __name__ == "__main__":
    main()
 
 
but results in 
 

Enter your Meraki API Key:

 

Reading VLAN 10...
Current DNS: HIDDEN
HIDDEN

 

Reading VLAN 11...
Current DNS: HIDDEN
HIDDEN

 

Proceed with DNS update? (yes/no): yes

 

Updating VLAN 10...
Payload: {'name': 'POS-PCI', 'subnet': 'HIDDEN', 'applianceIp': 'HIDDEN', 'dhcpHandling': 'Run a DHCP server', 'dhcpLeaseTime': '1 day', 'dhcpBootOptionsEnabled': False, 'dhcpOptions': [], 'dnsNameservers': '8.8.8.8,1.1.1.1'}

Update failed for VLAN 10: appliance, updateNetworkApplianceVlan - 400 Bad Request, {'errors': ['The Custom nameservers list contains one or more invalid entries (should be IP addresses or domain names).']}

 

 

 

1 Accepted Solution
alemabrahao
Kind of a big deal
Kind of a big deal

You sent a list (["8.8.8.8", "1.1.1.1"]). The endpoint schema expects a single string value.

You also sent a comma-separated string. While the user interface allows commas, the API parser is more demanding; try using a newline (\n) between the inputs.

I am not a Cisco Meraki employee. My suggestions are based on documentation of Meraki best practices and day-to-day experience.

Please, if this post was useful, leave your kudos and mark it as solved.

View solution in original post

6 Replies 6
alemabrahao
Kind of a big deal
Kind of a big deal

I believe the problem is the comma; try updating only one IP address to see the result.

I am not a Cisco Meraki employee. My suggestions are based on documentation of Meraki best practices and day-to-day experience.

Please, if this post was useful, leave your kudos and mark it as solved.
PhilipDAth
Kind of a big deal
Kind of a big deal

What I would do is setup a network how you want to be, and then use getNetworkApplianceVlan() to see how the data comes back for DNS.  Then you use that exact data format when calling updateNetworkApplianceVlan().

 

I don't know the answer, but my guess is it will need to be an array.

NEW_DNS = ["1.1.1.1","8.8.8.8"]

RaphaelL
Kind of a big deal
Kind of a big deal

Correct ! 

 

    "dhcpRelayServerIps": [
      "10.1.1.1",
      "10.2.2.2",
      "10.3.3.3",
      "10.4.4.4"
    ]
Dan_s_97
Conversationalist

unfortunately the same issue still 

VLAN 10: ERROR → appliance, updateNetworkApplianceVlan - 400 Bad Request, {'errors': ['The Custom nameservers list contains one or more invalid entries (should be IP addresses or domain names).']}
VLAN 11: ERROR → appliance, updateNetworkApplianceVlan - 400 Bad Request, {'errors': ['The Custom nameservers list contains one or more invalid entries (should be IP addresses or domain names).']}
VLAN 900: ERROR → appliance, updateNetworkApplianceVlan - 400 Bad Request, {'errors': ['The Custom nameservers list contains one or more invalid entries (should be IP addresses or domain names).']}

 

i tried the other way around 

Applying DNS updates...
VLAN 10: ERROR → appliance, updateNetworkApplianceVlan - 400 Bad Request, {'errors': ["'dnsNameservers' must be a string"]}
VLAN 11: ERROR → appliance, updateNetworkApplianceVlan - 400 Bad Request, {'errors': ["'dnsNameservers' must be a string"]}
VLAN 900: ERROR → appliance, updateNetworkApplianceVlan - 400 Bad Request, {'errors': ["'dnsNameservers' must be a string"]}

alemabrahao
Kind of a big deal
Kind of a big deal

You sent a list (["8.8.8.8", "1.1.1.1"]). The endpoint schema expects a single string value.

You also sent a comma-separated string. While the user interface allows commas, the API parser is more demanding; try using a newline (\n) between the inputs.

I am not a Cisco Meraki employee. My suggestions are based on documentation of Meraki best practices and day-to-day experience.

Please, if this post was useful, leave your kudos and mark it as solved.
Dan_s_97
Conversationalist

Thank you all 

final working code for anyone trying to do the same in future 

import meraki
from getpass import getpass

TARGET_NETWORK_NAME = "REDACTED_NETWORK_NAME"
VLANS_TO_UPDATE = [REDACTED_VLAN_ID_1, REDACTED_VLAN_ID_2]
NEW_DNS = "REDACTED_DNS_1\nREDACTED_DNS_2"

def main():
    API_KEY = getpass("Enter your Meraki API Key: ").strip()
    dashboard = meraki.DashboardAPI(api_key=API_KEY, print_console=False)

    org_id = dashboard.organizations.getOrganizations()[0]["id"]

    networks = dashboard.organizations.getOrganizationNetworks(
        org_id, total_pages='all'
    )

    net = next((n for n in networks if n["name"] == TARGET_NETWORK_NAME), None)
    if not net:
        print("Network not found")
        return

    net_id = net["id"]

    for vlan_id in VLANS_TO_UPDATE:
        print(f"\nReading VLAN {vlan_id}...")
        vlan = dashboard.appliance.getNetworkApplianceVlan(net_id, vlan_id)
        print("Current DNS:", vlan.get("dnsNameservers"))

    confirm = input("\nProceed with DNS update? (yes/no): ").lower()
    if confirm not in ("yes", "y"😞
        return

    for vlan_id in VLANS_TO_UPDATE:
        print(f"\nUpdating VLAN {vlan_id}...")

        vlan = dashboard.appliance.getNetworkApplianceVlan(net_id, vlan_id)

        payload = {
            "name": vlan["name"],
            "subnet": "REDACTED_SUBNET",
            "applianceIp": "REDACTED_APPLIANCE_IP",
            "dhcpHandling": vlan["dhcpHandling"],
            "dhcpLeaseTime": vlan["dhcpLeaseTime"],
            "dhcpBootOptionsEnabled": vlan["dhcpBootOptionsEnabled"],
            "dhcpOptions": vlan["dhcpOptions"],
            "dnsNameservers": NEW_DNS,
        }

        print("Payload:", payload)

        try:
            dashboard.appliance.updateNetworkApplianceVlan(
                net_id,
                vlan_id,
                **payload
            )
            print(f"Updated VLAN {vlan_id}")
        except Exception as e:
            print(f"Update failed for VLAN {vlan_id}: {e}")

if __name__ == "__main__":
    main()
Get notified when there are additional replies to this discussion.