Skip to content
This repository was archived by the owner on Apr 28, 2026. It is now read-only.
This repository was archived by the owner on Apr 28, 2026. It is now read-only.

Too many attributes being sent with Create and Update operations #53

Description

@dnesting

Presently the client serializes all attributes it knows about when sending Create and Update requests to the controller. By contrast, the official web UI only sends a subset of attributes that appear relevant. When retrieving resources with the Get operation, some attributes that the controller doesn't think we should care about get omitted, and others that we've set previously (that the controller never expected to see) get returned. Because we set far more attributes than the web UI sets, this results in two classes of bugs:

  1. There appears to be perpetual differences between local state and what's stored on the controller, because we are trying to set an attribute that the controller omits in its response. This results in Terraform diffs that never converge.
  2. When attributes that the controller isn't expecting are later made available to the web UI client, this causes the web UI to behave incorrectly. For instance, a network configured as WAN will show "LAN" on the network list. There may be more serious bugs lurking.

Acknowledging that this is a poorly-behaved API service (it's not exactly documented or supported), it's still an issue that needs a solution. Has anyone given this any thought?

It seems like there needs to be a few decisions:

  1. Do we try to fix this?
  2. How should we go about suppressing fields? How do we figure out what to suppress?
  3. Knowing the best plan for (2), do we still think this is a tractable problem?

I suggest:

  1. Yes
  2. Making requests, cataloging behavior, and hand-crafting a set of conditions that need to be true for a list of fields to exist in the request (and contribute to a diff), along with whether fields are required, and what their defaults are.
  3. I don't know.

For reference, here are some JSON blobs (sorted fields):

Network

Creating a WAN in the web UI:

{
  "name": "LTE",
  "purpose": "wan",
  "report_wan_event": true,
  "wan_dhcp_options": [],
  "wan_egress_qos": "",
  "wan_ip_aliases": [],
  "wan_load_balance_type": "failover-only",
  "wan_load_balance_weight": 50,
  "wan_networkgroup": "WAN2",
  "wan_type": "dhcp",
  "wan_type_v6": "disabled"
}

Retrieving this object back from the controller adds an _id and site attributes.

Creating a LAN in the web UI:

{
  "dhcp_relay_enabled": false,
  "dhcpd_dns_enabled": false,
  "dhcpd_enabled": true,
  "dhcpd_gateway_enabled": false,
  "dhcpd_leasetime": 86400,
  "dhcpd_start": "10.0.0.6",
  "dhcpd_stop": "10.0.0.254",
  "dhcpd_time_offset_enabled": false,
  "enabled": true,
  "gateway_type": "default",
  "ip_subnet": "10.0.0.1/24",
  "ipv6_interface_type": "none",
  "ipv6_pd_start": "::2",
  "ipv6_pd_stop": "::7d1",
  "is_nat": true,
  "name": "Test",
  "nat_outbound_ip_addresses": [],
  "networkgroup": "LAN",
  "purpose": "corporate",
  "vlan": "22",
  "vlan_enabled": true
}

Note the entirely different field sets, such as networkgroup.

Switch Port Profile

Separately, here's a GET of an existing switch port profile:

  {
   "_id": "...omitted...",
   "site_id": "...omitted...",
   "name": "IoT",
   "forward": "native",
   "isolation": false,
   "native_networkconf_id": "...omitted...",
   "attr_no_edit": true
  }

Here's the Terraform config:

resource "unifi_port_profile" "iot" {
  name                  = "IoT"
  native_networkconf_id = unifi_network.iot.id
}

But it sees this diff (with my commentary):

  ~ resource "unifi_port_profile" "iot" {
      ~ autoneg                        = false -> true  // the web UI says "link speed" = "Autonegotiate"
      + dot1x_ctrl                     = "force_authorized" // the web UI says "802.1X Control" = "Force authorized"
      ~ dot1x_idle_timeout             = 0 -> 300
        id                             = "...omitted..."
      ~ lldpmed_enabled                = false -> true // Enabled in the web UI
        name                           = "IoT"
      + op_mode                        = "switch"
      ~ stp_port_mode                  = false -> true // Enabled in the web UI
        # (25 unchanged attributes hidden)
    }

And here's what it sends to the controller:

{
 "_id": "5d6f172bf25e119aa7e3005e",
 "site_id": "default",
 "autoneg": true,
 "dot1x_ctrl": "force_authorized",
 "dot1x_idle_timeout": 300,
 "egress_rate_limit_kbps_enabled": false,
 "forward": "native",
 "full_duplex": false,
 "isolation": false,
 "lldpmed_enabled": true,
 "lldpmed_notify_enabled": false,
 "native_networkconf_id": "5d6f172bf25e119aa7e3005d",
 "name": "IoT",
 "op_mode": "switch",
 "port_security_enabled": false,
 "stormctrl_bcast_enabled": false,
 "stormctrl_mcast_enabled": false,
 "stormctrl_ucast_enabled": false,
 "stp_port_mode": true,
 "voice_networkconf_id": ""
}

(This particular update gets a 400 api.err.NoEdit but that's another issue.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions