From 325744645cc707e4694e14648b8f867e38c15c39 Mon Sep 17 00:00:00 2001 From: Rain Date: Wed, 30 Nov 2022 16:08:21 -0800 Subject: [PATCH] [wicketd] add stub API for fetching artifacts (#1998) Add a basic stub API for fetching artifacts, and update the OpenAPI schema. The implementation hasn't been filled out yet. --- openapi/wicketd.json | 54 +++++++++++++++++++++++++++++++++ wicketd/src/artifacts.rs | 40 ++++++++++++++++++++++++ wicketd/src/context.rs | 3 +- wicketd/src/http_entrypoints.rs | 24 +++++++++++++++ wicketd/src/lib.rs | 6 +++- 5 files changed, 125 insertions(+), 2 deletions(-) create mode 100644 wicketd/src/artifacts.rs diff --git a/openapi/wicketd.json b/openapi/wicketd.json index eae6f4a8ee..f30ea16cc9 100644 --- a/openapi/wicketd.json +++ b/openapi/wicketd.json @@ -10,6 +10,60 @@ "version": "0.0.1" }, "paths": { + "/artifacts/{name}/{version}/{hash}": { + "get": { + "summary": "Fetch an artifact from the in-memory cache.", + "operationId": "get_artifact", + "parameters": [ + { + "in": "path", + "name": "hash", + "description": "A hash of the artifact. TODO: is there a hash type?", + "required": true, + "schema": { + "type": "string" + }, + "style": "simple" + }, + { + "in": "path", + "name": "name", + "description": "The artifact's name.", + "required": true, + "schema": { + "type": "string" + }, + "style": "simple" + }, + { + "in": "path", + "name": "version", + "description": "The version of the artifact.", + "required": true, + "schema": { + "type": "string" + }, + "style": "simple" + } + ], + "responses": { + "200": { + "description": "", + "content": { + "*/*": { + "schema": {} + } + } + }, + "4XX": { + "$ref": "#/components/responses/Error" + }, + "5XX": { + "$ref": "#/components/responses/Error" + } + } + } + }, "/inventory": { "get": { "summary": "A status endpoint used to report high level information known to wicketd.", diff --git a/wicketd/src/artifacts.rs b/wicketd/src/artifacts.rs new file mode 100644 index 0000000000..a4323cea8f --- /dev/null +++ b/wicketd/src/artifacts.rs @@ -0,0 +1,40 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +// Copyright 2022 Oxide Computer Company + +use hyper::body::Bytes; +use schemars::JsonSchema; +use serde::Deserialize; +use slog::Logger; + +/// Path parameters for Silo requests +#[derive(Clone, Debug, Deserialize, JsonSchema)] +#[allow(dead_code)] +pub(crate) struct ArtifactId { + /// The artifact's name. + pub(crate) name: String, + + /// The version of the artifact. + pub(crate) version: String, +} + +/// The artifact store, used to cache artifacts. +pub struct ArtifactStore { + log: Logger, + // TODO: implement this +} + +impl ArtifactStore { + pub(crate) fn new(log: &Logger) -> Self { + let log = log.new(slog::o!("component" => "wicketd artifact store")); + Self { log } + } + + pub(crate) fn get_artifact(&self, id: &ArtifactId) -> Option { + slog::debug!(self.log, "Artifact requested (this is a stub implementation which always 404s): {:?}", id); + // TODO: implement this + None + } +} diff --git a/wicketd/src/context.rs b/wicketd/src/context.rs index fbe6ac0a1a..133e39496c 100644 --- a/wicketd/src/context.rs +++ b/wicketd/src/context.rs @@ -4,9 +4,10 @@ //! User provided dropshot server context -use crate::MgsHandle; +use crate::{artifacts::ArtifactStore, MgsHandle}; /// Shared state used by API handlers pub struct ServerContext { + pub artifact_store: ArtifactStore, pub mgs_handle: MgsHandle, } diff --git a/wicketd/src/http_entrypoints.rs b/wicketd/src/http_entrypoints.rs index b30b646e9d..fc1b2ac465 100644 --- a/wicketd/src/http_entrypoints.rs +++ b/wicketd/src/http_entrypoints.rs @@ -4,12 +4,16 @@ //! HTTP entrypoint functions for wicketd +use crate::artifacts::ArtifactId; use crate::RackV1Inventory; use dropshot::endpoint; use dropshot::ApiDescription; +use dropshot::FreeformBody; use dropshot::HttpError; use dropshot::HttpResponseOk; +use dropshot::Path; use dropshot::RequestContext; +use hyper::Body; use std::sync::Arc; use crate::ServerContext; @@ -22,6 +26,7 @@ pub fn api() -> WicketdApiDescription { api: &mut WicketdApiDescription, ) -> Result<(), String> { api.register(get_inventory)?; + api.register(get_artifact)?; Ok(()) } @@ -53,3 +58,22 @@ async fn get_inventory( } } } + +/// Fetch an artifact from the in-memory cache. +#[endpoint { + method = GET, + path = "/artifacts/{name}/{version}" +}] +async fn get_artifact( + rqctx: Arc>, + path: Path, +) -> Result, HttpError> { + match rqctx.context().artifact_store.get_artifact(&path.into_inner()) { + Some(bytes) => Ok(HttpResponseOk(Body::from(bytes).into())), + None => { + Err(HttpError::for_not_found(None, "Artifact not found".into())) + } + } +} + +// TODO: hash verification/fetch artifact by hash? diff --git a/wicketd/src/lib.rs b/wicketd/src/lib.rs index ca3b809f39..cdd4fc6f93 100644 --- a/wicketd/src/lib.rs +++ b/wicketd/src/lib.rs @@ -2,12 +2,14 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. +mod artifacts; mod config; mod context; mod http_entrypoints; mod inventory; mod mgs; +use artifacts::ArtifactStore; pub use config::Config; pub(crate) use context::ServerContext; pub use inventory::{RackV1Inventory, SpInventory}; @@ -58,6 +60,8 @@ pub async fn run_server(config: Config, args: Args) -> Result<(), String> { ..Default::default() }; + let artifact_store = ArtifactStore::new(&log); + let mgs_manager = MgsManager::new(&log, config.mgs_addr); let mgs_handle = mgs_manager.get_handle(); tokio::spawn(async move { @@ -67,7 +71,7 @@ pub async fn run_server(config: Config, args: Args) -> Result<(), String> { let server = dropshot::HttpServerStarter::new( &dropshot_config, http_entrypoints::api(), - ServerContext { mgs_handle }, + ServerContext { artifact_store, mgs_handle }, &log.new(o!("component" => "dropshot (wicketd)")), ) .map_err(|err| format!("initializing http server: {}", err))?