-
Notifications
You must be signed in to change notification settings - Fork 351
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
move the validation logic into executor #2258
Conversation
Codecov Report
Additional details and impacted files@@ Coverage Diff @@
## main #2258 +/- ##
==========================================
- Coverage 64.99% 64.88% -0.12%
==========================================
Files 129 129
Lines 15153 15178 +25
==========================================
- Hits 9849 9848 -1
- Misses 5304 5330 +26 |
@@ -46,6 +46,8 @@ pub trait CloneBoxExecutor { | |||
pub trait Executor: CloneBoxExecutor { | |||
/// Executes the workload | |||
fn exec(&self, spec: &Spec) -> Result<(), ExecutorError>; | |||
|
|||
fn validate(&self, spec: &Spec) -> Result<(), ExecutorError>; |
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.
validate
is one of the purposes of implementing this function. How about before_exec()
or something?
If I was a user of libcontainer
, I would like to know the environment in which the validate()
will run. e.g after the cgroup etc is applied
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.
There are a few things to unpack here. I would group before_exec
or similar functions into lifecycle hook category. OCI spec offers these. I am a little hesitant to expand this concept for the executor.
You raised a valid point that user would want to know the environment when validate runs. One potential solution is to extensively document the behavior. However, this will require the users to actually dig in the documentation (or comments) to understand this.
Currently, we are designing this based on a single usercase from runwasi. Is there another usecase we can look to?
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.
Currently, we are designing this based on a single usercase from runwasi. Is there another usecase we can look to?
I don't know for now. Why not create a new error(maybe ValidateError
) to narrow down usage for this interface?
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.
New error is hard. We provide an error interface for the trait without the actual implementation. There is no good way to know upfront what specific validation error should arise. Even with the executor error, we have a custom error as one of the type for this reason. The only error that can be handled is the can't handle
error.
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 was a little short in my explanation. My point is this:
#[derive(Debug, thiserror::Error)]
pub enum ExecutorValidateError {
#[error("{0} executor can't handle spec")]
CantHandle(&'static str),
}
pub trait Executor: CloneBoxExecutor {
/// Executes the workload
fn exec(&self, spec: &Spec) -> Result<(), ExecutorError>;
/// Validate if the spec can be executed by the executor. This step runs
/// after the container init process is created, entered into the correct
/// namespace and cgroups, and pivot_root into the rootfs. But this step
/// runs before waiting for the container start signal.
fn validate(&self, spec: &Spec) -> Result<(), ExecutorValidateError>;
}
I think exec()
and validate()
will return the different types of errors. They should be fundamentally separated.
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 see. Done.
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 generally agree, but I left the comment.
May I ask you to write the migration guide? |
@yihuaf thanks! this approach looks like it would help address the challenges we ran into on the runwasi side |
@yihuaf , If you rebase with current main, I have started a doc for this in one of my PRs. You can extend that, or re-write that (the existing points in it are few) as needed. |
if name.contains('/') && PathBuf::from(name).exists() { | ||
return Some(PathBuf::from(name)); | ||
} | ||
for path in path_var.split(':') { |
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 know that this PR just moved code but I want to raise the concern where @jprendes raised here: containerd/runwasi#156 (comment)
The issue is that the is_executable
check should be inside of the for loop, not outside. @jprendes provides an example of illustrating why that's the case.
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.
To allow more flexibility for the executor, we move the validate logic into the executor. The validate runs in the `create` step before workloads are executed. Instead of implementing the validation in the `exec`, to maintain backward competiability, we have to introduce an extra step. The exec is too late to fail if the spec is not validated. Signed-off-by: yihuaf <[email protected]>
Signed-off-by: yihuaf <[email protected]>
bf26d3f
to
4867118
Compare
Signed-off-by: yihuaf <[email protected]>
Signed-off-by: yihuaf <[email protected]>
To allow more flexibility for the executor, we move the validate logic into the executor. The validate runs in the
create
step before workloads are executed. Instead of implementing the validation in theexec
, to maintain backward competiability, we have to introduce an extra step. The exec is too late to fail if the spec is not validated.