Skip to content

Conversation

rcgoodfellow
Copy link
Contributor

@rcgoodfellow rcgoodfellow commented Jul 4, 2024

We have a transactional API for port settings objects. The port settings object is somewhat complex. The port settings object returned by GET requests to view port settings is not exactly the same as the port settings object used to create/update port settings with PUT/POST requests. This makes it rather grueling to manage port settings.

This PR adds client-side read/modify/write routines for managing individual items within port settings such as addresses.

Also pulls in the observability stuff from #661.

An example of using these new commands is here, which demonstrates creating a new BGP connection to a cloud provider. An example of using the observability stuff pulled in from #661 is in this comment analyzing an Omicron bug.

Comment on lines 110 to 356
enum Port {
Qsfp0,
Qsfp1,
Qsfp2,
Qsfp3,
Qsfp4,
Qsfp5,
Qsfp6,
Qsfp7,
Qsfp8,
Qsfp9,
Qsfp10,
Qsfp11,
Qsfp12,
Qsfp13,
Qsfp14,
Qsfp15,
Qsfp16,
Qsfp17,
Qsfp18,
Qsfp19,
Qsfp20,
Qsfp21,
Qsfp22,
Qsfp23,
Qsfp24,
Qsfp25,
Qsfp26,
Qsfp27,
Qsfp28,
Qsfp29,
Qsfp30,
Qsfp31,
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I wonder if this is something that could live in the API? Lists like this could be difficult to maintain the same in various clients 🤔

Additionally, if our customers were to create their own clients from our API, they might find it pretty hard to know that this enum is required

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The network configuration API is going to be changing pretty significantly based on some work @internet-diglett is doing to eventually support things like terraform integration. A resource-based model is ultimately where we want to go. This PR is to make things reasonable for operators until that larger chunk of API work lands. It's my hope that at a CLI level, these commands will remain pretty much the same, while their internal implementation will benefit from broader API work, and things like this, which you rightfully note should be captured by the API will go away.

Copy link
Contributor

Choose a reason for hiding this comment

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

gotcha, thanks for the clarification!

Comment on lines 324 to 344
let links: HashMap<String, LinkConfigCreate> = current
.links
.iter()
.enumerate()
.map(|(i, x)| {
(
format!("phy{}", i),
LinkConfigCreate {
autoneg: x.autoneg,
fec: x.fec,
lldp: LldpServiceConfigCreate {
//TODO
enabled: false,
lldp_config: None,
},
mtu: x.mtu,
speed: x.speed,
},
)
})
.collect();
Copy link
Contributor

Choose a reason for hiding this comment

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

same as above

@rcgoodfellow rcgoodfellow marked this pull request as ready for review July 6, 2024 00:15
@rcgoodfellow rcgoodfellow force-pushed the port-settings-update branch from 61b3892 to 7f3fecb Compare July 9, 2024 06:53
@rcgoodfellow
Copy link
Contributor Author

Copy link
Collaborator

@ahl ahl left a comment

Choose a reason for hiding this comment

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

  • this "net" vs "networking" subcommand seems confusing
  • I'd suggest we add some testing of these commands
  • positional arguments are (I think) new to the CLI; I think we should stick with - and -- prefixed arguments for clarity (but if that seems cumbersome for these, let me know--recall we do have completion that is inclusive of arguments)
  • consider docs on subcommands and internal nodes
  • I think there a few places we want to use .stream() rather than .send

}

#[async_trait]
impl RunnableCmd for CmdNet {
Copy link
Collaborator

Choose a reason for hiding this comment

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

this is the only thing that needs to impl RunnableCmd

Copy link
Contributor Author

Choose a reason for hiding this comment

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

All of the subcommands still need the Context object, so I found the interface convenient to reuse. Is there a different approach you would suggest?

]
},
{
"name": "net",
Copy link
Collaborator

Choose a reason for hiding this comment

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

so we're going to have "networking" and "net" as top-level subcommands? this seems confusing.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

net has been removed, and the commands have been integrated into the existing command hierarchy.

#[derive(Parser, Debug, Clone)]
#[command(verbatim_doc_comment)]
#[command(name = "net bgp status")]
pub struct CmdBgpStatus {}
Copy link
Collaborator

Choose a reason for hiding this comment

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

now does this differ from system networking bgp status?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The only difference is the output is formatted a bit nicer. Seems like this would fit in better as a flag to system networking bgp status? Something like --output table? This is likely true of several commands in this PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ry@masaka:~$ oxide net bgp status
switch0
=======
Peer Address  Local ASN  Remote ASN  Session State  State Duration
169.254.30.1  65547      64502       Established    1h 5m 33s 942ms
169.254.10.1  65547      64500       Established    1h 5m 38s 910ms

switch1
=======
Peer Address  Local ASN  Remote ASN  Session State  State Duration
169.254.20.1  65547      64500       Established    1h 5m 38s 855ms
169.254.40.1  65547      64502       Established    1h 5m 33s 888ms
ry@masaka:~$ oxide system networking bgp status
[
  {
    "addr": "169.254.30.1",
    "local_asn": 65547,
    "remote_asn": 64502,
    "state": "established",
    "state_duration_millis": 3943140,
    "switch": "switch0"
  },
  {
    "addr": "169.254.10.1",
    "local_asn": 65547,
    "remote_asn": 64500,
    "state": "established",
    "state_duration_millis": 3948107,
    "switch": "switch0"
  },
  {
    "addr": "169.254.20.1",
    "local_asn": 65547,
    "remote_asn": 64500,
    "state": "established",
    "state_duration_millis": 3948072,
    "switch": "switch1"
  },
  {
    "addr": "169.254.40.1",
    "local_asn": 65547,
    "remote_asn": 64502,
    "state": "established",
    "state_duration_millis": 3943104,
    "switch": "switch1"
  }
]

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For the moment, opting to have show commands that display information in a more human-oriented way than their status and view counterparts.

.body(BgpAnnounceSetCreate {
announcement: current,
name: self.announce_set.clone(),
description: self.announce_set.to_string(), //TODO?
Copy link
Collaborator

Choose a reason for hiding this comment

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

is this the description we want?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've made this configurable

Comment on lines +1050 to +1066
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct MacAddr {
a: [u8; 6],
}

#[derive(Serialize, Deserialize, Clone, Debug)]
struct LinkStatus {
address: MacAddr,
enabled: bool,
autoneg: bool,
fec: String,
link_state: String,
fsm_state: String,
media: String,
speed: String,
}

Copy link
Collaborator

Choose a reason for hiding this comment

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

how fragile is this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Quite. The link status endpoint is experimental and opaque, passing just Object back. We could, in theory, import types from Dendrite, which is where these types ultimately come from, but that repo is not open, so there are challenges on that front.

@morlandi7 morlandi7 added this to the 9 milestone Jul 10, 2024
@rcgoodfellow
Copy link
Contributor Author

rcgoodfellow commented Jul 11, 2024

For testing, I've added an expectorate test for the one command that produces stable output: oxide system networking switch-port-settings show. The other commands are either strictly modifiers and don't return any output or are hooked up to an API endpoint that is not stable yet and returns an Object, making strongly typed testing a bit of a challenge and perhaps not worthwhile until the interface stabilizes in the API.

Copy link
Collaborator

@ahl ahl left a comment

Choose a reason for hiding this comment

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

great stuff!

Comment on lines +21 to +22
SwitchInterfaceConfigCreate, SwitchInterfaceKind, SwitchInterfaceKind2, SwitchLocation,
SwitchPort, SwitchPortConfigCreate, SwitchPortGeometry, SwitchPortGeometry2,
Copy link
Collaborator

Choose a reason for hiding this comment

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

it's concerning to me that we've managed to have these types suffixed with 2 which indicates a name conflict, but that's a problem for another day. I should probably have some sort of lint check for that.

Comment on lines 37 to 62
#[derive(Parser, Debug, Clone)]
#[command(verbatim_doc_comment)]
#[command(name = "port")]
pub struct CmdPort {
#[clap(subcommand)]
subcmd: PortSubCommand,
}

#[async_trait]
impl RunnableCmd for CmdPort {
async fn run(&self, ctx: &Context) -> Result<()> {
match &self.subcmd {
PortSubCommand::Config(cmd) => cmd.run(ctx).await,
PortSubCommand::Status(cmd) => cmd.run(ctx).await,
}
}
}

#[derive(Parser, Debug, Clone)]
enum PortSubCommand {
/// Manage port configuration.
Config(CmdPortConfig),

/// Observe port status.
Status(CmdPortStatus),
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

can this all be deleted?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yep sure can! removed

Status(CmdPortStatus),
}

#[derive(Parser, Debug, Clone)]
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't claim to really understand what this does, but perhaps a short doc comment explaining very briefly the command and (probably) that the subcommands are short-hand for common operations one could perform via system networking switch-port-settings create; if it's easy enough, I think a short doc comment on all the new commands and their subcommands would be great.

Comment on lines +359 to +365
/// Prefixes to allow for the peer.
#[clap(long, conflicts_with = "no_filtering")]
allowed: Vec<oxnet::IpNet>,

/// Do not filter.
#[clap(long, conflicts_with = "allowed")]
no_filtering: bool,
Copy link
Collaborator

Choose a reason for hiding this comment

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

nice

@rcgoodfellow rcgoodfellow merged commit 18d1196 into main Jul 11, 2024
@rcgoodfellow rcgoodfellow deleted the port-settings-update branch July 11, 2024 05:54
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.

4 participants