-
Notifications
You must be signed in to change notification settings - Fork 254
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
Validate target environments #2806
base: main
Are you sure you want to change the base?
Conversation
30aa1fc
to
3b25dad
Compare
e74895b
to
828cb70
Compare
Checking environments adds an appreciable bump to the time to run We could, of course, assume that environments are immutable, and key the cache by package reference instead of digest. But that would certainly be an assumption and not guaranteed to be true. |
This is now sort of a thing and can possibly be looked at. Outstanding questions:
Possibly longer term questions:
If folks want to play with this, add the following to your favourite [application]
targets = ["spin:[email protected]"] and set your wkg config (~/.config/wasm-pkg/config.toml) to: default_registry = "registrytest-vfztdiyy.fermyon.app"
[registry."registrytest-vfztdiyy.fermyon.app"]
type = "oci" (No, that is not the cat walking across the keyboard... this is my test registry which backs onto my ghcr.) |
I'd suggest "next to the code that implements them"; ideally generated by that code. |
crates/build/src/manifest.rs
Outdated
let dt = deployment_targets_from_manifest(&manifest); | ||
Ok((bc, dt, Ok(manifest))) | ||
} | ||
Err(e) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not obvious to me what's happening here. It reads like we're trying to get build and deployment configs even when we can't parse the manifest? I think some terse one-line comments on each branch of this match
would go a long way to helping this be a bit more understandable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reading the code more, I'm unsure why we go through all these great lengths to read the targets config here when later on we only seem to run the targets check if the manifest was successfully parsed. Won't this information just be thrown away?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rylev You are absolutely right - this was a holdover from an earlier iteration before I realised I was going to need to full manifest - thanks for catching it. I've pared this back to "has deployment targets", which I think is worth keeping so we can warn if the manifest errors have caused us to bypass checking.
crates/build/src/manifest.rs
Outdated
Ok((bc, dt, Ok(manifest))) | ||
} | ||
Err(e) => { | ||
let bc = fallback_load_build_configs(&manifest_file).await?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems like there's some need for better error messages here through liberal use of .context
. As the code stands now, component_build_configs
function might return an error saying only "expected table found some other type" which would be very confusing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On reflection these should preserve (and immediately return) the original manifest load error rather than blatting it with whatever went awry during the fallback attempt.
crates/build/src/manifest.rs
Outdated
let table: toml::value::Table = toml::from_str(&manifest_text)?; | ||
let target_environments = table | ||
.get("application") | ||
.and_then(|a| a.as_table()) | ||
.and_then(|t| t.get("targets")) | ||
.and_then(|arr| arr.as_array()) | ||
.map(|v| v.as_slice()) | ||
.unwrap_or_default() | ||
.iter() | ||
.filter_map(|t| t.as_str()) | ||
.map(|s| s.to_owned()) | ||
.collect(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would serializing to a type through serde::Deserialize
making this easier to read?
crates/build/src/manifest.rs
Outdated
@@ -57,6 +75,30 @@ async fn fallback_load_build_configs( | |||
}) | |||
} | |||
|
|||
async fn fallback_load_deployment_targets( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: is "deployment targets" the right nomenclature? That sounds like what you would be targeting for spin deploy
and not the environment you're targeting. Perhaps we could play with the wording here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rylev I'm very open to naming on "deployment targets." The current name emerged in a woolly manner from a sense of "these are possible targets for deployment" or "the target environments we want to be able to deploy to." I do feel, albeit not strongly, that it's worth specifying 'deployment' (cf. e.g. 'compilation target') - but for sure let's improve this!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"runtime targets"?
async fn load_component_source(&self, source: &Self::Component) -> anyhow::Result<Vec<u8>>; | ||
async fn load_dependency_source(&self, source: &Self::Dependency) -> anyhow::Result<Vec<u8>>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we implementing ComponentSourceLoader
more than once? I'm a bit lost why we need the flexibility of defining the type of dependency and component instead of hard coding. Can you explain what this buys us?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current build system doesn't create a lockfile. The current composition implementation depends on the locked types (because it runs at trigger time). This allows us to implement composition on the raw AppManifest as well as on the LockedApp.
"# | ||
); | ||
|
||
let doc = wac_parser::Document::parse(&wac_text) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We really should implement a programatic API in wac
for this so that we don't need to manipulate a wac script.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah! I tried constructing a wac document AST, which seemed cleaner than parsing a document, but I foundered on - if memory serves - something as trivial as the miette
spans. I tried it with dummy spans but something internal seems to have been trying to use the length of the name in error or something and anyway there was anguish. Using the underlying model would have been awesome, but was (for me) hard to understand and to line up inputs for.
crates/environments/src/loader.rs
Outdated
} | ||
|
||
pub async fn load_and_resolve_all<'a>( | ||
app: &'a spin_manifest::schema::v2::AppManifest, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: seems like we pass app
and resolution_context
around a lot. It might be nicer to put those into a Resolver
struct and implement these functions as methods on that struct.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had an explore of this, and have pushed something like it as a separate commit for easy reversion. I ended up naming the proposed struct ApplicationToValidate
because otherwise I ended up with no "application" visible in a module that was ostensibly all about validating applications. I still have mixed feelings but there's definitely some nice aspects to encapsulating the component loading stuff - I was able to tuck some more clutter away and split things up in a way that's hopefully more readable...
@itowlson I think that's an okay assumption to make, personally. Perhaps paired with a way to flush the local cache explicitly? |
We could also consider introducing something like |
4870bba
to
531e4fb
Compare
Okay I have pencilled in |
Aren't environments also just packages though? Ones that we apply some additional semantics to, yes, but not ones that are someone non-standard. Which actually raises the question: could we use the exact packages to generate bindings for Spin and the SDKs as well? (Not necessarily as part of this effort, but as a future thing.) |
Signed-off-by: itowlson <[email protected]>
Signed-off-by: itowlson <[email protected]>
Signed-off-by: itowlson <[email protected]>
Signed-off-by: itowlson <[email protected]>
Signed-off-by: itowlson <[email protected]>
Signed-off-by: itowlson <[email protected]>
Signed-off-by: itowlson <[email protected]>
Signed-off-by: itowlson <[email protected]>
Signed-off-by: itowlson <[email protected]>
51a09f4
to
76cb8af
Compare
Signed-off-by: itowlson <[email protected]>
Implemented caching on the basis of immutability as per Till's comment #2806 (comment) (and double checked on Windows). I'll have a think about the lockfile idea. A lockfile mapping environment IDs to digests would allow us to reuse the existing Wasm by-digest caching infra instead of having something custom for name-based lookup. If we generated it into ETA: I implemented Till's lockfile-based cache strategy. It does make some things cleaner for sure. I've done it as a separate commit for now, but will squash once we agree on it. |
Signed-off-by: itowlson <[email protected]>
EXTREMELY WIP.There are plenty of outstanding questions here (e.g.
environment definition,Redis trigger,hybrid componentisation), and reintegration work (e.g. composing dependencies before validating)(ETA: component dependencies now work).In its current state, the PR is more for visibility than out of any sense of readiness. Also, it has not had any kind of tidying pass, so a lot of naming is not great.But it does work, sorta kinda, some of the time. So we progress.
cc @tschneidereit