Skip to content

Return all LLDP configs for each switch port settings object #8665

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

internet-diglett
Copy link
Contributor

  • We allowed multiple LLDP link configs to be created on a single switch port settings object, but we would only return one when viewing the object. This has been fixed.

  • Note that until we support breakout connections, only one lldp configuration will be applied. This is not a regression.

Related

Resolves #8640

* We allowed multiple LLDP link configs to be created on a single
  switch port settings object, but we would only return one when
  viewing the object. This has been fixed.

* Note that until we support breakout connections, only one lldp
  configuration will be applied. This is not a regression.
@internet-diglett internet-diglett changed the title Return all LLDP configs for each link Return all LLDP configs for each switch port settings object Jul 23, 2025
Comment on lines +125 to +129
management_ip: Some(
"203.0.113.10"
.parse()
.expect("management_ip should be a valid address"),
),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setting the management_ip to Some triggers a 500 error in my local environment:

        FAIL [   5.922s] omicron-nexus::test_all integration_tests::switch_port::test_port_settings_basic_crud
  stdout ───

    running 1 test
    test integration_tests::switch_port::test_port_settings_basic_crud ... FAILED

    failures:

    failures:
        integration_tests::switch_port::test_port_settings_basic_crud

    test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 453 filtered out; finished in 5.82s

  stderr ───
    log file: /tmp/test_all-7489d72104d534f7-test_port_settings_basic_crud.19830.0.log
    note: configured to log to "/tmp/test_all-7489d72104d534f7-test_port_settings_basic_crud.19830.0.log"
    DB URL: postgresql://root@[::1]:56635/omicron?sslmode=disable
    DB address: [::1]:56635
    log file: /tmp/test_all-7489d72104d534f7-test_port_settings_basic_crud.19830.2.log
    note: configured to log to "/tmp/test_all-7489d72104d534f7-test_port_settings_basic_crud.19830.2.log"

    thread 'integration_tests::switch_port::test_port_settings_basic_crud' panicked at nexus/tests/integration_tests/switch_port.rs:174:6:
    called `Result::unwrap()` on an `Err` value: expected status code 201 Created, found 500 Internal Server Error

Upon looking into the logs I found this message:

23:27:44.137Z INFO b324e6ed-86b6-4096-82d2-c06317d1f86e (dropshot_external): request completed
    error_message_external = Internal Server Error
    error_message_internal = Unknown diesel error creating SwitchPortSettings called "portofino": Error deserializing field 'management_ip': invalid network address f
ormat. returned type isn't a Inet
    latency_us = 64232
    local_addr = 127.0.0.1:38416
    method = POST
    remote_addr = 127.0.0.1:39650
    req_id = 62680343-d827-4d25-9cd4-7ff21655065a
    response_code = 500
    uri = /v1/system/networking/switch-port-settings

Which is quite puzzling because the contents of the field appear to be valid:

    [
       LldpLinkConfig {
           id: 686fdcad-7fe2-444f-b2e7-3e22de4c836a,
           enabled: true,
           link_name: Some(
               "Link Name",
           ),
           link_description: Some(
               "link_ Dscription",
           ),
           chassis_id: Some(
               "Chassis ID",
           ),
           system_name: Some(
               "System Name",
           ),
           system_description: Some(
               "System description",
           ),
           management_ip: Some(
               V4(
                   Ipv4Network {
                       addr: 203.0.113.10,
                       prefix: 32,
                   },
               ),
           ),
           time_created: 2025-07-23T00:58:55.447616202Z,
           time_modified: 2025-07-23T00:58:55.447616202Z,
           time_deleted: None,
       },
   ]

We also appear to be inserting structs with Option<IpNetwork> fields in other parts of our db-queries. I will look more into this tomorrow.

Copy link
Contributor

@jgallagher jgallagher Jul 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unknown diesel error creating SwitchPortSettings called "portofino": Error deserializing field 'management_ip': invalid network address f
ormat. returned type isn't a Inet

This is a serialization error from diesel; it's failing to deserialize the response from cockroach. This almost always means there's a mismatch between the types defined in the database and what we've told diesel the types are. I think that's the case here too; in dbinit.sql, the management_ip column is specified as TEXT:

management_ip TEXT,

but in the diesel schema, it's specified as Inet:

management_ip -> Nullable<Inet>,

I think this means:

  • No query fetching a non-NULL value for this column can ever succeed
  • If you're only seeing it in your local env, that probably means we had no tests that exercise a non-NULL value for this column until this change

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW this was top of mind because @sudomateo ran into the same thing in #8587, where #6693 had made some changes to a type in the diesel schema but not the database, but we didn't catch it in CI because there were similarly no tests for non-NULL values.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jgallagher Great catch, thanks for the insight!

@sudomateo
Copy link
Contributor

Just noting that the latest changes here work correctly with Terraform now since the API is returning the correct results.

> terraform apply

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following
symbols:
  + create

Terraform will perform the following actions:

  # oxide_project.example will be created
  + resource "oxide_project" "example" {
      + description   = "example"
      + id            = (known after apply)
      + name          = "example"
      + time_created  = (known after apply)
      + time_modified = (known after apply)
    }

  # oxide_switch_port_settings.example will be created
  + resource "oxide_switch_port_settings" "example" {
      + addresses     = [
          + {
              + addresses = [
                  + {
                      + address        = "0.0.0.0/0"
                      + address_lot_id = "64ffed7d-c9e5-4456-8880-72ce52068ecc"
                    },
                ]
              + link_name = "phy0"
            },
        ]
      + description   = "example"
      + id            = (known after apply)
      + links         = [
          + {
              + autoneg   = false
              + link_name = "phy0"
              + lldp      = {
                  + enabled = true
                }
              + mtu       = 1500
              + speed     = "speed1_g"
            },
          + {
              + autoneg   = false
              + link_name = "phy1"
              + lldp      = {
                  + enabled = true
                }
              + mtu       = 1500
              + speed     = "speed1_g"
            },
        ]
      + name          = "example"
      + port_config   = {
          + geometry = "qsfp28x1"
        }
      + routes        = [
          + {
              + link_name = "phy0"
              + routes    = [
                  + {
                      + dst = "0.0.0.0/0"
                      + gw  = "0.0.0.0"
                    },
                ]
            },
        ]
      + time_created  = (known after apply)
      + time_modified = (known after apply)
    }

Plan: 2 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

oxide_project.example: Creating...
oxide_switch_port_settings.example: Creating...
oxide_switch_port_settings.example: Creation complete after 0s [id=ad3dc048-39c0-4089-a4da-5ca6c5354212]
oxide_project.example: Creation complete after 1s [id=9ff9aac3-d613-4a05-a40c-84d7d6b2678c]

Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
~/o/t/tf ((00555be5))> terraform plan
oxide_project.example: Refreshing state... [id=9ff9aac3-d613-4a05-a40c-84d7d6b2678c]
oxide_switch_port_settings.example: Refreshing state... [id=ad3dc048-39c0-4089-a4da-5ca6c5354212]

No changes. Your infrastructure matches the configuration.

Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

When creating multiple links with lldp_link_config enabled, the API response does not show them both as enabled
3 participants