Skip to content
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

System Update API #2100

Merged
merged 50 commits into from
Jan 30, 2023
Merged

System Update API #2100

merged 50 commits into from
Jan 30, 2023

Conversation

david-crespo
Copy link
Contributor

@david-crespo david-crespo commented Dec 29, 2022

RFD 348 is still in progress, but I find it helpful to do this in parallel.


This is a big PR, but fortunately it is very straightforward: endpoints plus the service functions, models, and tables you'd expect to see backing those endpoints. It's a good time to add "updateable" to your computer's dictionary.

Included here

  • Endpoints
    • System version + status (updating or not + reason)
    • Get tree of updateable components (each w/ version + status)
    • List system updates
    • Get system update
    • Get tree of component updates for top-level system update
    • Start update (noop, returns placeholder SystemUpdateDeployment)
    • Stop update (noop)
    • Change existing refresh endpoint to match new /v1/system/update/... convention
  • Nexus functions for all that except start and stop
    • Basic tests that create the thing and then retrieve it
  • Tables
    • System updates
    • Component updates
    • Join table between system updates and component updates
    • Updateable components
    • Update deployments
  • Weird stuff
    • version_sort column on system_update and component_update that lets us hack in sorting by version
    • Enforce maximum major/minor/patch version number because version_sort relies on zero-padding
    • Make system update semver version the PK for the system updates table and fetch by version in endpoints
      • Ideally we'd be able to fetch by ID also, but there would been a lot of boilerplate to make it work like NameOrId without comparable value due to the latter's reuse in many places. Version is unique and immutable, so this should be good enough to start.

Conspicuously missing, to be done in followups

  • nexus functions for updating updateable component rows (possibly also system updates and component updates — not sure if they're supposed to be modified)
  • Actually do an update

Do a find for TODO: for an embarrassing number of additional bullets.

Open questions

// pub high: semver::Version,
pub low: String,
pub high: String,
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@smklein if we want to use semver::Version here, which sounds sensible, we need to wrap it and impl JsonSchema on that. Correct?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I believe so - looks like someone already started work on this here: GREsau/schemars#195

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good timing. I looked but apparently in the wrong place.

@@ -479,6 +479,8 @@ pub enum VersionStatus {
pub struct SystemVersion {
pub version_range: VersionRange,
pub status: VersionStatus,
// TODO: time_released? time_last_applied? I got a fever and the only
Copy link
Collaborator

Choose a reason for hiding this comment

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

🐮🔔

@david-crespo david-crespo changed the title Stub System Update API System Update API Dec 29, 2022
system_user_list /system/user
system_user_view /system/user/{user_name}
system_version /v1/system/update/version
Copy link
Contributor Author

Choose a reason for hiding this comment

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

IF (big IF) we don't have anything else hanging off of /system/update other than what's here, seems like we could get away without doing my goofy /update/updates idea if we put system version and component version tree under /system/version. So:

system_update_list                       /v1/system/updates
system_update_view                       /v1/system/updates/{update_id}
system_update_components_list            /v1/system/updates/{update_id}/components
system_update_start                      /v1/system/updates/{update_id}/start
system_update_stop                       /v1/system/updates/{update_id}/stop

system_version                           /v1/system/version
system_component_version_list            /v1/system/version/components

This has the disadvantage of putting version under a different top-level key, which makes it less obvious how closely tied it is to the /system/updates endpoints.

Copy link
Contributor

Choose a reason for hiding this comment

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

I much prefer this. The /system/update/updates pattern is fairly different than the rest of our API where typically resources are plural.

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 problem is this: what do we do when want to add another endpoint that should go under /updates? With /system/update/updates we just add /system/update/other_thing. With /system/updates we can't do /system/updates/other_thing.

Copy link
Contributor Author

@david-crespo david-crespo Jan 5, 2023

Choose a reason for hiding this comment

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

I forgot, we already have one (which is at /system/updates because it preexisted my current work):

/// Refresh update data
#[endpoint {
method = POST,
path = "/system/updates/refresh",
tags = ["system"],
}]
async fn updates_refresh(
rqctx: Arc<RequestContext<Arc<ServerContext>>>,
) -> Result<HttpResponseUpdatedNoContent, HttpError> {

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't guess dropshot would let you register /system/updates/refresh before /system/updates/{update_id} to have it automatically be handled, would it? 😅. There's actually no overlap in this case because refresh isn't a valid UUID. If that worked, it'd be sort of ideal.

Beyond that, I'm not really sure. I obviously don't think we should stall on this API decision and I'm fine with moving forward with what's here. Hopefully we'll figure out a better way to do this at some point and update accordingly.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, Dropshot would have to be modified: oxidecomputer/dropshot#199

And more and more I agree with the comments on that issue arguing it’s a footgun.

@david-crespo
Copy link
Contributor Author

david-crespo commented Dec 29, 2022

@smklein so far it seems like we'll need the following tables. Maybe we can pair tomorrow on throwing something basic in.

  • system updates
  • component updates
  • join table associating system updates and component updates
  • component version and status
  • update in progress

System version + status response would be put together by looking at the update in progress table for the status and pulling the low and high versions from the list of components.


/* Unique semver version */
/* TODO: If the version is really supposed to be unique, we could make it the PK? */
version STRING(40) NOT NULL,

This comment was marked as resolved.

david-crespo added a commit that referenced this pull request Jan 2, 2023
…her file (#2102)

I noticed two things while working on #2100.

1. `AssetIdentityMetadata` is defined in `views.rs`, but it is used by
both DB models and views. To me that makes it not primarily a view, so
it should go in a different file. I moved it to
`nexus/types/src/identity.rs`, where `Asset` is defined.
2. Instead of the `identity()` method for copying around the identity
metadata (which `Resource` has), there is a `impl From<T: Asset> for
AssetIdentityMetadata`, which is perfectly fine, but I think it's nicer
to have them be the same.

As far as I remember, these are accidents of history and not for any
particular reason.
@david-crespo david-crespo enabled auto-merge (squash) January 30, 2023 18:43
@david-crespo david-crespo merged commit 35cf540 into main Jan 30, 2023
@david-crespo david-crespo deleted the stub-update-api branch January 30, 2023 18:53
david-crespo added a commit that referenced this pull request Feb 10, 2023
Closes #2344. Followup to #2100. Rather than manually adding a sortable
`version_sort` column alongside the `version` column, make
`SemverVersion` itself automatically sortable by serializing it to the
DB in sortable form (with zero padding on the numbers). On
deserialization, we remove the padding before trying to parse it.
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.

3 participants