[MGS] Reject SP reset requests to our own sled#8830
Conversation
hawkw
left a comment
There was a problem hiding this comment.
Nice to see the first use of structured dropshot errors in practice! I left a couple ltitle notes, but this looks good to me --- perhaps worth waiting to hear from Dave or Karen though for the meat of it.
| /// Helper trait for error types we can get from various gateway_client API | ||
| /// calls. | ||
| /// | ||
| /// For each error type, we need to know whether we should retry the request (by | ||
| /// sending it to the next MGS instance). | ||
| pub(super) trait RetryableMgsError: fmt::Display { | ||
| fn should_try_next_mgs(&self) -> bool; |
There was a problem hiding this comment.
Take it or leave it: I wonder if this ought to be in gateway-client? There's other code in Nexus that has similar behavior of attempting a request through both MGSes that could also use this...
There was a problem hiding this comment.
I can see that, although I worry slightly that this is already a little update-specific. If it were in gateway-client I'd be tempted to call it err.is_retryable(), except the real driver for this at all is to be able to say "if you get back SpComponentResetError::ResetSpOfLocalSled, you must send the request to the other MGS". So it's not really "retryable" so much as "you might have success if you tried the other MGS instead of this one". Maybe the name should reflect that more precisely, and then it would be fine to put it in gateway-client?
karencfv
left a comment
There was a problem hiding this comment.
Thanks for setting these safeguards! I have a few minor questions
| fn status_code(&self) -> ErrorStatusCode { | ||
| match self { | ||
| SpComponentResetError::ResetSpOfLocalSled => { | ||
| ErrorStatusCode::BAD_REQUEST |
There was a problem hiding this comment.
I'm on the fence about this status code. Would a 403 not be more suitable? A 400 may imply that the request is malformed?
There was a problem hiding this comment.
Ehh, maybe? I think of 403 as being for auth problems; I used 400 because this is a malformed request semantically (calling "reset sled 14's SP" is not a legal request to the MGS on switch 0). But I also think this doesn't really matter, so if 403 seems like a better fit I'm happy to change it.
There was a problem hiding this comment.
I used 400 because this is a malformed request semantically (calling "reset sled 14's SP" is not a legal request to the MGS on switch 0)
Fair enough! I leave it to you to go with either one
| allow_local_sled_sp_reset = true | ||
|
|
||
| [[switch.location.description]] | ||
| name = "switch1" | ||
| local_sled = 1 | ||
| allow_local_sled_sp_reset = true |
There was a problem hiding this comment.
This is the config file that is used for systems like a4x2. Would we not want it to emulate a behaviour that is closer to the real thing to avoid potential bugs? Or, more concretely, in which cases do we anticipate wanting to reset an sp-sim on it's own local sled here?
There was a problem hiding this comment.
The thing I was mainly concerned about was any unit or integration tests where we're doing simulated SP resets today. For any of those, I disabling resets if the fake SP thinks it's connected to a particular sled is just a headache with no benefit.
I'm a lot less sure about a4x2, but also it just doesn't really work anyway? Resetting an SP in a4x2 doesn't do anything, because it's not hooked up to the "sleds" in any meaningful way. Or in other words - I think for this to matter we'd need to be in an environment where we're testing upgrades, and we can't do that in a4x2 without a lot of work. I defaulted to true here in case there were any unit tests that happened to use this config file. I could change it to false and see if anything breaks, though?
There was a problem hiding this comment.
I'm a lot less sure about a4x2, but also it just doesn't really work anyway? Resetting an SP in a4x2 doesn't do anything, because it's not hooked up to the "sleds" in any meaningful way. Or in other words - I think for this to matter we'd need to be in an environment where we're testing upgrades, and we can't do that in a4x2 without a lot of work.
Fair 🤔. I think I was mostly concerned about someone developing something against an a4x2 only to find that it's buggy when testing against a racklette. It'd be nice to catch something like this beforehand.
I could change it to false and see if anything breaks, though?
That'd be nice! But also I guess I don't feel sufficiently strongly to push for it. I leave it up to you whether we change this or not!
|
Testing on And similarly, from switch zone 1, I can reset everything except its own local sled: |
| allow_local_sled_sp_reset = true | ||
|
|
||
| [[switch.location.description]] | ||
| name = "switch1" | ||
| local_sled = 1 | ||
| allow_local_sled_sp_reset = true |
There was a problem hiding this comment.
I'm a lot less sure about a4x2, but also it just doesn't really work anyway? Resetting an SP in a4x2 doesn't do anything, because it's not hooked up to the "sleds" in any meaningful way. Or in other words - I think for this to matter we'd need to be in an environment where we're testing upgrades, and we can't do that in a4x2 without a lot of work.
Fair 🤔. I think I was mostly concerned about someone developing something against an a4x2 only to find that it's buggy when testing against a racklette. It'd be nice to catch something like this beforehand.
I could change it to false and see if anything breaks, though?
That'd be nice! But also I guess I don't feel sufficiently strongly to push for it. I leave it up to you whether we change this or not!
| fn status_code(&self) -> ErrorStatusCode { | ||
| match self { | ||
| SpComponentResetError::ResetSpOfLocalSled => { | ||
| ErrorStatusCode::BAD_REQUEST |
There was a problem hiding this comment.
I used 400 because this is a malformed request semantically (calling "reset sled 14's SP" is not a legal request to the MGS on switch 0)
Fair enough! I leave it to you to go with either one
Fixes #8768 by implementing "option 1" from that issue's proposed solutions:
sp_component_reset()that can cleanly report this particular kind of failure.This is definitely the first custom dropshot error in MGS (although we need some others: #8013, #8014, #8350), and maybe the first in omicron more generally? The server side is pretty straightforward, I think, but the client side ended up being a little messy. I'm not sure how much of that is because of the rework I had to do to
try_all_serially()vs the inherent changes (e.g., the fact that we have a different progenitor error type for this one endpoint).I'll definitely put this on a racklette before merging, but this should be close enough to review, and I'm very interested in feedback about integrating the custom error type.