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

Modified provider checks to be version independant #193

Merged
merged 7 commits into from
Oct 18, 2023

Conversation

aish-where-ya
Copy link
Contributor

@aish-where-ya aish-where-ya commented Oct 12, 2023

Feature or Problem

Bug: Providers deployed in a manifest on a link name needed to have a unique image reference associated with it. This allowed for providers with the same reference but different versions to be created on the same link name.

Fix: This PR improves upon this issue by associating an image ref, regardless of the version, with a link name. By ignoring the version, we permit only unique image references into the manifest/lattice.

Related Issues

Release Information

next

Consumer Impact

Capabilities with duplicate image refs will be removed.

Testing

manually tested

Built on platform(s)

  • x86_64-linux
  • aarch64-linux
  • x86_64-darwin
  • aarch64-darwin
  • x86_64-windows

Tested on platform(s)

  • x86_64-linux
  • aarch64-linux
  • x86_64-darwin
  • aarch64-darwin
  • x86_64-windows

Unit Test(s)

Modified test_manifest_validation

Acceptance or Integration

Updated e2e test named e2e_upgrades to check for provider versioning

Manual Verification

manually verified.

Signed-off-by: aish-where-ya <[email protected]>
Copy link
Member

@brooksmtownsend brooksmtownsend left a comment

Choose a reason for hiding this comment

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

This does explicitly block people from pushing different providers to the same image repository, but I think that's an okay assertion 🤔

Thoughts @thomastaylor312?

@aish-where-ya
Copy link
Contributor Author

We can always pick the other route and explicitly perform checks against the version. It would involve retrieving items from the linkedef hash map, splitting it into reference and version and performing checks for this specific case where the user is trying to put in an existing provider with a different version.

I'm thinking about cases where the approach in the PR will fail/succeed to catch what the other approach can/cannot. This one is a lesser number of steps that's all.

@connorsmith256
Copy link
Contributor

Does wadm have access to the lattice's metadata KV bucket? If so, wadm should be able to translate from the providers' image ref to its public key, which might be a better test for uniqueness

@autodidaddict
Copy link
Member

Does wadm have access to the lattice's metadata KV bucket? If so, wadm should be able to translate from the providers' image ref to its public key, which might be a better test for uniqueness

The image ref to public key lookup can be gleaned from making a control interface API request for the claims cache. Giving wadm direct access to buckets like those of the lattice cache can be potentially problematic in some production scenarios, especially multi-tenant and high security.

Copy link
Member

@brooksmtownsend brooksmtownsend left a comment

Choose a reason for hiding this comment

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

A couple requests for small efficiency improvements 🙂

return;
}
};
if stored_manifest.name() != name {
Copy link
Member

Choose a reason for hiding this comment

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

I think a comment here would be helpful to indicate that we don't want to compare to other versions of this application since upgrading versions is a valid scenario

}
};
if stored_manifest.name() != name {
if let Some(deployed_manifest) = stored_manifest.get_version(deployed_version) {
Copy link
Member

Choose a reason for hiding this comment

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

Consider using stored_manifest.get_deployed to simplify this loop

Comment on lines 538 to 552
if let Some(deployed_version) = &model_summary.deployed_version {
let (stored_manifest, _) = match self
.store
.get(account_id, lattice_id, &model_summary.name)
.await
{
Ok(Some(m)) => m,
Ok(None) => (StoredManifest::default(), 0),
Err(e) => {
error!(error = %e, "Unable to fetch data");
self.send_error(msg.reply, "Internal storage error".to_string())
.await;
return;
}
};
Copy link
Member

Choose a reason for hiding this comment

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

I think if you use the suggestion in the above comment with get_deployed you can get rid of this check altogether 😄

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Modifying the check instead of removing since we don't want to perform a fetch operation if there is no currently deployed version.

Comment on lines 581 to 585
} else {
manifests.get_current()
}
}
None => manifests.get_current(),
Copy link
Member

Choose a reason for hiding this comment

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

If we can't get the version that we requested, we actually want to send an error back to the sender (see below.) It may be worth moving this check up above where you start looking through the manifests so that we can early-failure ack

if !manifests.deploy(req.version) {
            trace!("Requested version does not exist");
            self.send_reply(
                msg.reply,
                // NOTE: We are constructing all data here, so this shouldn't fail, but just in
                // case we unwrap to nothing
                serde_json::to_vec(&DeployModelResponse {
                    result: DeployResult::Error,
                    message: format!(
                        "Model with the name {name} does not have the specified version to deploy"
                    ),
                })
                .unwrap_or_default(),
            )
            .await;
            return;

Comment on lines 597 to 599
let image_ref_split: Vec<&str> = image_name.split(':').collect();
if let (Some(&ref_link), Some(&ref_version)) =
(image_ref_split.first(), image_ref_split.last())
Copy link
Member

Choose a reason for hiding this comment

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

This shows up in a place or two, if it makes sense consider a function like

fn parse_image_ref_and_tag(image_name: &str) -> Option<(String, String)>

I'm bad at naming but you get the idea 😄

Comment on lines 604 to 609
"Provider {image_name} is currently deployed. Forbidden operation.",
);
self.send_error(
msg.reply,
format!(
"Provider {image_name} is currently deployed. Forbidden operation."
Copy link
Member

Choose a reason for hiding this comment

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

Is there a way here to indicate which model is deployed with the offending provider?

Suggested change
"Provider {image_name} is currently deployed. Forbidden operation.",
);
self.send_error(
msg.reply,
format!(
"Provider {image_name} is currently deployed. Forbidden operation."
"Provider {image_name} is currently deployed with a different version. Forbidden operation.",
);
self.send_error(
msg.reply,
format!(
"Provider {image_name} is currently deployed with a different version. Forbidden operation."

@brooksmtownsend brooksmtownsend merged commit e0f9bc1 into wasmCloud:main Oct 18, 2023
5 checks passed
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.

4 participants