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

Implement wasi-config #2869

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft

Implement wasi-config #2869

wants to merge 1 commit into from

Conversation

itowlson
Copy link
Contributor

Fixes #2868.

This has the same considerations as our wasi-observe and wasi-keyvalue implementations in terms of versioning the Spin worlds - I mashed it into the existing Spin 2 worlds for development and testing but know that is not sustainable. (At this point, I'm assuming all this lot will be punted into a new Spin 3 world.)

I'm publishing this mostly to:

  1. see if it works
  2. give us the chance to look at implementation considerations and decide if we need to offer feedback to upstream proposal

(Regarding 2, it felt like we have some errors that don't map nicely to the proposal. I ended up using the io error variant for anything that wasn't a provider error, which feels potentially misleading. @kate-goldenring I'd value your thoughts on this!)

@@ -31,6 +31,7 @@ impl Factor for VariablesFactor {
fn init<T: Send + 'static>(&mut self, mut ctx: InitContext<T, Self>) -> anyhow::Result<()> {
ctx.link_bindings(spin_world::v1::config::add_to_linker)?;
ctx.link_bindings(spin_world::v2::variables::add_to_linker)?;
ctx.link_bindings(spin_world::wasi::config::store::add_to_linker)?;
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 we'll want to consider whether we want to make this configurable for users of the factor - i.e., do we want to force all runtimes that use the VariablesFactor to link all three interfaces? We could instead make this linking conditional based on some configuration provided when the factor is constructed.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Crate feature flag?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Seems like the feature is light-weight enough that we could just do a dynamic check instead of a compile time feature flag, but I don't feel strongly either way.

];
ensure_matches!(get_all(), Ok(val) if val == expected_all);

ensure_matches!(get("invalid-name"), Err(Error::Io(_)));
Copy link
Collaborator

Choose a reason for hiding this comment

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

Does wasi-config actually say anything about how keys are supposed to be formed? Is it possible that some code that targets wasi-config and runs properly on other runtimes would error on Spin?

Copy link
Contributor

Choose a reason for hiding this comment

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

No it doesn't: https://github.com/WebAssembly/wasi-runtime-config/blob/f4d699bc6dd77adad99fa1a2246d482225ec6485/wit/store.wit#L17

This is a good call out of how it should probably be opinionated about string fmt or support invalid-name error

@@ -0,0 +1,8 @@
# Variables
Copy link
Collaborator

Choose a reason for hiding this comment

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

We should consider adding a conformance test for this. The runtime tests here are meant to be Spin CLI specific but this test seems like it should be applied to all Spin compliant runtimes.

@@ -52,6 +52,21 @@ impl ProviderResolver {
self.resolve_template(template).await
}

pub async fn resolve_all(&self, component_id: &str) -> Result<Vec<(String, String)>> {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit: doc comment.

.map(|r| r.map(|value| (key.to_string(), value)))
});

futures::future::try_join_all(resolve_futs).await
Copy link
Collaborator

Choose a reason for hiding this comment

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

I am slightly worried about performance - at some point we might want to see if adding some sort of caching mechanism to providers is worth it.

Copy link
Collaborator

Choose a reason for hiding this comment

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

We should probably push this down into the provider as e.g. (untested):

trait Provider {
    async fn get(&self, key: &Key) -> anyhow::Result<Option<String>>;

    async fn get_many(&self, keys: impl IntoIterator<Item = &Key>) -> anyhow::Result<impl IntoIterator<Option<String>>> {
        try_join_all(keys.into_iter().map(|key| self.get(key)).await
    }
}

match <Self as variables::Host>::get(self, key).await {
Ok(value) => Ok(Some(value)),
// Err(e) if matches!(e, variables::Error::Undefined(_)) => Ok(Ok(None)),
Err(e) => {
Copy link
Collaborator

Choose a reason for hiding this comment

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

FWIW you could:

Err(variables::Error::Undefined(_)) => Ok(None)

variables::Error::Undefined(msg) => spin_world::wasi::config::store::Error::Io(msg), // TODO: this should presumably not occur here
variables::Error::InvalidName(msg) => {
spin_world::wasi::config::store::Error::Io(msg)
} // TODO: this doesn't feel ideal, but wasi-config only allows two error cases
Copy link
Contributor

Choose a reason for hiding this comment

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

Regarding 2, it felt like we have some errors that don't map nicely to the proposal. I ended up using the io error variant for anything that wasn't a provider error, which feels potentially misleading.

@itowlson referencing your PR comment and this comment inline, I talked to @thomastaylor312 and InvalidName seems like a good example of an error message we'd want to update WASI config to use as it is a fairly universal case

variables::Error::Provider(msg) => {
spin_world::wasi::config::store::Error::Upstream(msg)
}
variables::Error::Other(msg) => spin_world::wasi::config::store::Error::Io(msg), // TODO: again, hard to know how to map this (and the original expressions::Error is not more helpful)
Copy link
Contributor

Choose a reason for hiding this comment

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

WASI config does seem to define IO errors as everything else. Is the concern you are raising is that we are labeling this "other" error as related to IO when it might not be?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@kate-goldenring Yes, that's exactly my worry. I appreciate that ""other" is a kind of unhelpful bucket though...!

];
ensure_matches!(get_all(), Ok(val) if val == expected_all);

ensure_matches!(get("invalid-name"), Err(Error::Io(_)));
Copy link
Contributor

Choose a reason for hiding this comment

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

No it doesn't: https://github.com/WebAssembly/wasi-runtime-config/blob/f4d699bc6dd77adad99fa1a2246d482225ec6485/wit/store.wit#L17

This is a good call out of how it should probably be opinionated about string fmt or support invalid-name error

@itowlson
Copy link
Contributor Author

@kate-goldenring re #2869 (comment) can you clarify "no it doesn't" please? I didn't follow how the linked WIT comment applied - are you thinking of this as "we can't possibly find a key for an invalid name so should return Ok(None)" kind of thing?

@kate-goldenring
Copy link
Contributor

@kate-goldenring re #2869 (comment) can you clarify "no it doesn't" please? I didn't follow how the linked WIT comment applied - are you thinking of this as "we can't possibly find a key for an invalid name so should return Ok(None)" kind of thing?

@itowlson I was aiming to point out that this is a weak spot of the WASI config interface and that we should propose updating it to either (A) be opinionated about string formatting or (B) support and invalid key error. My preference is that latter; however, the former would help achieve @rylev's point of enabling more portability across host implementatations.

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.

Support wasi-config
4 participants