Skip to content

Run a Wasm file as an application without a manifest#2479

Merged
itowlson merged 1 commit intospinframework:mainfrom
itowlson:manifestless
May 26, 2024
Merged

Run a Wasm file as an application without a manifest#2479
itowlson merged 1 commit intospinframework:mainfrom
itowlson:manifestless

Conversation

@itowlson
Copy link
Collaborator

Fixes #2477. Or at least it explores what a solution might look like - there are definitely other paths to consider.

For example, this goes the route of constructing an in-memory spin.toml, because the route from spin.toml to locked app to trigger is well-exercised. But we could bypass that and construct a lockfile directly - a lot of spin.toml concerns are not (yet) relevant to manifestless applications.

Or we could start planning more extensively for Future Things - this POC doesn't really provide any support in terms of the OCI proposal.

One thing we discussed internally was whether to put this on spin up or on a new command such as spin serve (by analogy with wasmtime serve). For the sake of this POC I put it on spin up and inferred "bare file or manifest" based on the file extension. This is not intended as a proposal, just a thing to dangle the actual loader code off.

Anyway hopefully provides us with something to argue about grin

match spin_common::paths::resolve_manifest_file_path(path.into()) {
Ok(file) => Self::File(file),
Ok(file) => {
if file.extension().and_then(std::ffi::OsStr::to_str) == Some("wasm") {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Might be nice to support *.wat as well. If we want to be really precise we can use wasmparser to peek the special bytes to determine if the file is Wasm.

Copy link
Collaborator

Choose a reason for hiding this comment

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

we can use wasmparser to peek the special bytes

...or bytes.starts_with(b"\x00asm") 🙂

Copy link
Collaborator

Choose a reason for hiding this comment

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

we can use wasmparser to peek the special bytes

...or bytes.starts_with(b"\x00asm") 🙂

...or https://github.com/bytecodealliance/wasm-tools/blob/755abb691d9d401dad542b8f238d19e6f3624e16/crates/wat/src/lib.rs#L228 😸

Copy link
Collaborator

Choose a reason for hiding this comment

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

I SUPPOSE

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is absolutely world class bikeshedding, keep it up

Copy link
Member

Choose a reason for hiding this comment

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

To add to the bikeshedding — do we actually expect users to try this with .wat?

Copy link
Collaborator

@fibonacci1729 fibonacci1729 May 1, 2024

Choose a reason for hiding this comment

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

Most tools in this space accept either wat or wasm interchangeably, so yes...

Copy link
Collaborator

Choose a reason for hiding this comment

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

I mean no, I don't think we expect users to use .wat, but also it isn't that hard to support apart from this slight inconvenience in detecting file type.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

For now I have checked for the .wasm and .wat extensions, and isolated the "is it a Wasm file" logic into a function that we can evolve with magic numbers and wasmparsers and other such wild excesses if and when people feel strongly about it. And by "we" I mean you Brian

@itowlson
Copy link
Collaborator Author

Folks, do we have any thoughts on whether to take this forward in its current form? (Ignoring the detail of how we identify Wasm files.)

@lann
Copy link
Collaborator

lann commented May 21, 2024

I remain in favor of my proposal 🙂

@tschneidereit
Copy link
Contributor

IIUC this would not provide a way to do any IO, because that would require having anything allow-listed, right? If so, I think that's a perfectly valid starting point, but it might make sense to see if we could at least provide slightly better error messages? Such as telling folks that if they want to do outbound http, they have to use a manifest?

@itowlson
Copy link
Collaborator Author

@lann Which proposal do you mean?

@lann
Copy link
Collaborator

lann commented May 21, 2024

@lann Which proposal do you mean?

#2477

@itowlson
Copy link
Collaborator Author

@tschneidereit That would require either threading "did the app come from a loose Wasm file" all the way through Spin, or majorly reworking our error reporting architecture.

This would be a case where the Target Worlds proposal would be helpful, because we can give manifestless apps an implicit target world that doesn't include outbound HTTP, KV stores, etc. etc. Target world validation would, I'm pretty sure, happen at a time and level where we are still threading the origin info through, so it would be easy to customise the world validation failure to talk about supplying a manifest.

If that's correct, then we could either punt this until after Target Worlds, or go ahead with this accepting that the errors will be suboptimal for now, with a view to sorting them out in the TW timeframe.

@tschneidereit
Copy link
Contributor

@itowlson that makes sense, and I agree that if getting to better error messages right now is too hard, then that's okay because as you say we have other things in flight that should get us there :)

@itowlson
Copy link
Collaborator Author

Next discussion topic is do we put this on spin up or create a new spin serve / spin run / spin something-else command (to avoid any confusion likely to arise from flags being likely different across the manifestful and manifestless apps).

@lann
Copy link
Collaborator

lann commented May 23, 2024

I think spin up is fine. "Manifestless" really means "we create a secret manifest for you", right?

@itowlson itowlson marked this pull request as ready for review May 23, 2024 23:05
Copy link
Collaborator

@lann lann left a comment

Choose a reason for hiding this comment

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

A few non-blocking suggestions; looks great!


/// Load a Spin locked app from a standalone Wasm file.
pub async fn from_wasm_file(wasm_path: impl AsRef<Path>) -> Result<LockedApp> {
let app_root = std::env::current_dir()?;
Copy link
Collaborator

Choose a reason for hiding this comment

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

I would feel slightly better if we used a tempdir here. It shouldn't make any difference as the feature currently works, but as features are added I wouldn't want to accidentally expose content from the cwd.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Actually, I believe you already have working_dir where this function is called; could probably just pass that through.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is the directory relative to which to resolve the Wasm file reference (and, perhaps, in future, other paths). If we use working_dir then we have to copy the Wasm file first (before copying it again), and any file-related errors will show unexpected locations.

The alternative is for app_root to be the directory containing the Wasm file, and to override wasm_path to be only the name of the Wasm file (so that the relative reference resolves correctly), but I'm not sure that's going to be helpful with hypothetical future features where the user will expect paths entered on the CLI to be resolved relative to the current directory. Of course it's hard to know because we haven't defined those features yet!

We could also do a more invasive change that threads multiple "app roots" through the loader, or redefines the app root, or absolutises everything earlier. Or we can have a separate loader path for much longer than this PR does it, e.g. doing any copies needed then jumping straight to building the lockfile instead of leaning on the existing manifestful path.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Sounds complicated. I retract my feelings.

Direct,
}

fn single_file_manifest(wasm_path: impl AsRef<Path>) -> spin_manifest::schema::v2::AppManifest {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think you could get away with using the toml! macro here, which would be much less and code and easier to read.

pub enum AppSource {
File(PathBuf),
OciRegistry(String),
BareWasm(PathBuf),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should we add an explicit CLI arg (e.g. --from-wasm) for this path like we have for the other app sources?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, I had wondered about this. I'm concerned it would make the docs a bit confusing, given that --from-file (in the current proposal) also accepts Wasm files (because my lawyers inform me that Wasm files are files within the meaning of the Act). I suppose we could deprecate --from-file and define a new --from-manifest flag that forces the file to be interpreted as TOML, but this feels excessive. Although maybe I'll feel differently if I understand what #2529 is about.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe it would be better to instead have an orthogonal option to differentiate between manifestful and manifestless sources. Anyway, that ought to be backward compatible with this so definitely not a blocker here.

Signed-off-by: itowlson <ivan.towlson@fermyon.com>
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.

Proposal: "Manifest-less" Single Component Apps

5 participants