-
Notifications
You must be signed in to change notification settings - Fork 159
add lifecycle validation #558
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| package main | ||
|
|
||
| import ( | ||
| "fmt" | ||
| "io/ioutil" | ||
| "os" | ||
| "os/exec" | ||
| "path/filepath" | ||
| "strings" | ||
| "time" | ||
|
|
||
| tap "github.com/mndrix/tap-go" | ||
| rspec "github.com/opencontainers/runtime-spec/specs-go" | ||
| "github.com/opencontainers/runtime-tools/specerror" | ||
| "github.com/opencontainers/runtime-tools/validation/util" | ||
| uuid "github.com/satori/go.uuid" | ||
| ) | ||
|
|
||
| func main() { | ||
| t := tap.New() | ||
| t.Header(0) | ||
|
|
||
| g := util.GetDefaultGenerator() | ||
|
|
||
| var output string | ||
| config := util.LifecycleConfig{ | ||
| Actions: util.LifecycleActionCreate | util.LifecycleActionStart | util.LifecycleActionDelete, | ||
| PreCreate: func(r *util.Runtime) error { | ||
| r.SetID(uuid.NewV4().String()) | ||
|
|
||
| output = filepath.Join(r.BundleDir, g.Spec().Root.Path, "output") | ||
| poststart := rspec.Hook{ | ||
| Path: fmt.Sprintf("%s/%s/bin/sh", r.BundleDir, g.Spec().Root.Path), | ||
| Args: []string{ | ||
| "sh", "-c", fmt.Sprintf("echo 'post-start called' >> %s", output), | ||
| }, | ||
| } | ||
|
|
||
| g.AddPostStartHook(poststart) | ||
| g.SetProcessArgs([]string{"sh", "-c", fmt.Sprintf("echo 'process called' >> %s", "/output")}) | ||
| r.SetConfig(g) | ||
| return nil | ||
| }, | ||
| PostCreate: func(r *util.Runtime) error { | ||
| outputData, err := ioutil.ReadFile(output) | ||
| if err == nil { | ||
| if strings.Contains(string(outputData), "post-start called") { | ||
| return specerror.NewError(specerror.PoststartTiming, fmt.Errorf("The post-start hooks MUST be called before the `start` operation returns"), rspec.Version) | ||
| } else if strings.Contains(string(outputData), "process called") { | ||
| return specerror.NewError(specerror.ProcNotRunAtResRequest, fmt.Errorf("The user-specified program (from process) MUST NOT be run at this time"), rspec.Version) | ||
| } | ||
| return fmt.Errorf("File %v should not exist", output) | ||
| } | ||
| return nil | ||
| }, | ||
| PreDelete: func(r *util.Runtime) error { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I suggest we can add 'start' will return immediately, although 'echo' runs fast, but we are not sure how many time it costs. (for example, in runc/cc/Kata project) |
||
| util.WaitingForStatus(*r, util.LifecycleStatusStopped, time.Second*10, time.Second) | ||
| outputData, err := ioutil.ReadFile(output) | ||
| if err != nil { | ||
| return fmt.Errorf("%v\n%v", specerror.NewError(specerror.PoststartHooksInvoke, fmt.Errorf("The poststart hooks MUST be invoked by the runtime"), rspec.Version), specerror.NewError(specerror.ProcImplement, fmt.Errorf("The runtime MUST run the user-specified program, as specified by `process`"), rspec.Version)) | ||
| } | ||
| switch string(outputData) { | ||
| case "post-start called\n": | ||
| return specerror.NewError(specerror.ProcImplement, fmt.Errorf("The runtime MUST run the user-specified program, as specified by `process`"), rspec.Version) | ||
| case "process called\n": | ||
| fmt.Fprintln(os.Stderr, "WARNING: The poststart hook invoke fails") | ||
| return nil | ||
| case "post-start called\nprocess called\n": | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. since 'post-start' runs in 'create', the sequence here is wrong. |
||
| return specerror.NewError(specerror.PoststartTiming, fmt.Errorf("The post-start hooks MUST be called after the user-specified process is executed"), rspec.Version) | ||
| case "process called\npost-start called\n": | ||
| return nil | ||
| default: | ||
| return fmt.Errorf("Unsupported output information: %v", string(outputData)) | ||
| } | ||
| }, | ||
| } | ||
|
|
||
| err := util.RuntimeLifecycleValidate(g, config) | ||
| if err != nil { | ||
| diagnostic := map[string]string{ | ||
| "error": err.Error(), | ||
| } | ||
| if e, ok := err.(*exec.ExitError); ok { | ||
| if len(e.Stderr) > 0 { | ||
| diagnostic["stderr"] = string(e.Stderr) | ||
| } | ||
| } | ||
| t.YAML(diagnostic) | ||
| } | ||
|
|
||
| t.AutoPlan() | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,109 @@ | ||
| package main | ||
|
|
||
| import ( | ||
| "errors" | ||
| "fmt" | ||
| "io/ioutil" | ||
| "os" | ||
| "os/exec" | ||
| "path/filepath" | ||
| "strings" | ||
| "time" | ||
|
|
||
| tap "github.com/mndrix/tap-go" | ||
| rspec "github.com/opencontainers/runtime-spec/specs-go" | ||
| "github.com/opencontainers/runtime-tools/specerror" | ||
| "github.com/opencontainers/runtime-tools/validation/util" | ||
| uuid "github.com/satori/go.uuid" | ||
| ) | ||
|
|
||
| func main() { | ||
| t := tap.New() | ||
| t.Header(0) | ||
|
|
||
| g := util.GetDefaultGenerator() | ||
|
|
||
| var output string | ||
| config := util.LifecycleConfig{ | ||
| Actions: util.LifecycleActionCreate | util.LifecycleActionStart | util.LifecycleActionDelete, | ||
| PreCreate: func(r *util.Runtime) error { | ||
| r.SetID(uuid.NewV4().String()) | ||
|
|
||
| output = filepath.Join(r.BundleDir, g.Spec().Root.Path, "output") | ||
| poststop := rspec.Hook{ | ||
| Path: fmt.Sprintf("%s/%s/bin/sh", r.BundleDir, g.Spec().Root.Path), | ||
| Args: []string{ | ||
| "sh", "-c", fmt.Sprintf("echo 'post-stop called' >> %s", output), | ||
| }, | ||
| } | ||
|
|
||
| g.AddPostStopHook(poststop) | ||
| g.SetProcessArgs([]string{"sh", "-c", fmt.Sprintf("echo 'process called' >> %s", "/output")}) | ||
| r.SetConfig(g) | ||
| return nil | ||
| }, | ||
| PostCreate: func(r *util.Runtime) error { | ||
| outputData, err := ioutil.ReadFile(output) | ||
| if err == nil { | ||
| if strings.Contains(string(outputData), "post-stop called") { | ||
| return specerror.NewError(specerror.PoststopTiming, fmt.Errorf("The post-stop hooks MUST be called after the container is deleted"), rspec.Version) | ||
| } else if strings.Contains(string(outputData), "process called") { | ||
| return specerror.NewError(specerror.ProcNotRunAtResRequest, fmt.Errorf("The user-specified program (from process) MUST NOT be run at this time"), rspec.Version) | ||
| } | ||
| return fmt.Errorf("File %v should not exist", output) | ||
| } | ||
| return nil | ||
| }, | ||
| PreDelete: func(r *util.Runtime) error { | ||
| util.WaitingForStatus(*r, util.LifecycleStatusStopped, time.Second*10, time.Second) | ||
| outputData, err := ioutil.ReadFile(output) | ||
| if err != nil { | ||
| return specerror.NewError(specerror.ProcImplement, fmt.Errorf("The runtime MUST run the user-specified program, as specified by `process`"), rspec.Version) | ||
| } | ||
| switch string(outputData) { | ||
| case "post-stop called\n": | ||
| return fmt.Errorf("%v\n%v", specerror.NewError(specerror.PoststopTiming, fmt.Errorf("The post-stop hooks MUST be called after the container is deleted"), rspec.Version), specerror.NewError(specerror.ProcImplement, fmt.Errorf("The runtime MUST run the user-specified program, as specified by `process`"), rspec.Version)) | ||
| case "process called\n": | ||
| return nil | ||
| case "post-stop called\nprocess called\n", "process called\npost-stop called\n": | ||
| return specerror.NewError(specerror.PoststopTiming, fmt.Errorf("The post-stop hooks MUST be called after the container is deleted"), rspec.Version) | ||
| default: | ||
| return fmt.Errorf("Unsupported output information: %v", string(outputData)) | ||
| } | ||
| }, | ||
| PostDelete: func(r *util.Runtime) error { | ||
| outputData, err := ioutil.ReadFile(output) | ||
| if err != nil { | ||
| return fmt.Errorf("%v\n%v", specerror.NewError(specerror.PoststopHooksInvoke, fmt.Errorf("The poststop hooks MUST be invoked by the runtime"), rspec.Version), specerror.NewError(specerror.ProcImplement, fmt.Errorf("The runtime MUST run the user-specified program, as specified by `process`"), rspec.Version)) | ||
| } | ||
| switch string(outputData) { | ||
| case "post-stop called\n": | ||
| return specerror.NewError(specerror.ProcImplement, fmt.Errorf("The runtime MUST run the user-specified program, as specified by `process`"), rspec.Version) | ||
| case "process called\n": | ||
| fmt.Fprintln(os.Stderr, "WARNING: The poststop hook invoke fails") | ||
| return nil | ||
| case "post-stop called\nprocess called\n": | ||
| return errors.New("The Post-stop should called after the user-specified program command is executed") | ||
| case "process called\npost-stop called\n": | ||
| return nil | ||
| default: | ||
| return fmt.Errorf("Unsupported output information: %v", string(outputData)) | ||
| } | ||
| }, | ||
| } | ||
|
|
||
| err := util.RuntimeLifecycleValidate(g, config) | ||
| if err != nil { | ||
| diagnostic := map[string]string{ | ||
| "error": err.Error(), | ||
| } | ||
| if e, ok := err.(*exec.ExitError); ok { | ||
| if len(e.Stderr) > 0 { | ||
| diagnostic["stderr"] = string(e.Stderr) | ||
| } | ||
| } | ||
| t.YAML(diagnostic) | ||
| } | ||
|
|
||
| t.AutoPlan() | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,91 @@ | ||
| package main | ||
|
|
||
| import ( | ||
| "fmt" | ||
| "io/ioutil" | ||
| "os/exec" | ||
| "path/filepath" | ||
| "strings" | ||
| "time" | ||
|
|
||
| tap "github.com/mndrix/tap-go" | ||
| rspec "github.com/opencontainers/runtime-spec/specs-go" | ||
| "github.com/opencontainers/runtime-tools/specerror" | ||
| "github.com/opencontainers/runtime-tools/validation/util" | ||
| uuid "github.com/satori/go.uuid" | ||
| ) | ||
|
|
||
| func main() { | ||
| t := tap.New() | ||
| t.Header(0) | ||
|
|
||
| g := util.GetDefaultGenerator() | ||
|
|
||
| var output string | ||
| config := util.LifecycleConfig{ | ||
| Actions: util.LifecycleActionCreate | util.LifecycleActionStart | util.LifecycleActionDelete, | ||
| PreCreate: func(r *util.Runtime) error { | ||
| r.SetID(uuid.NewV4().String()) | ||
|
|
||
| output = filepath.Join(r.BundleDir, g.Spec().Root.Path, "output") | ||
| prestart := rspec.Hook{ | ||
| Path: fmt.Sprintf("%s/%s/bin/sh", r.BundleDir, g.Spec().Root.Path), | ||
| Args: []string{ | ||
| "sh", "-c", fmt.Sprintf("echo 'pre-start called' >> %s", output), | ||
| }, | ||
| } | ||
|
|
||
| g.AddPreStartHook(prestart) | ||
| g.SetProcessArgs([]string{"sh", "-c", fmt.Sprintf("echo 'process called' >> %s", "/output")}) | ||
| r.SetConfig(g) | ||
| return nil | ||
| }, | ||
| PostCreate: func(r *util.Runtime) error { | ||
| outputData, err := ioutil.ReadFile(output) | ||
| if err == nil { | ||
| if strings.Contains(string(outputData), "pre-start called") { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I always get this in 'runc'. |
||
| return specerror.NewError(specerror.PrestartTiming, fmt.Errorf("Pre-start hooks MUST be called after the `start` operation is called"), rspec.Version) | ||
| } else if strings.Contains(string(outputData), "process called") { | ||
| return specerror.NewError(specerror.ProcNotRunAtResRequest, fmt.Errorf("The user-specified program (from process) MUST NOT be run at this time"), rspec.Version) | ||
| } | ||
|
|
||
| return fmt.Errorf("File %v should not exist", output) | ||
| } | ||
| return nil | ||
| }, | ||
| PreDelete: func(r *util.Runtime) error { | ||
| util.WaitingForStatus(*r, util.LifecycleStatusStopped, time.Second*10, time.Second) | ||
| outputData, err := ioutil.ReadFile(output) | ||
| if err != nil { | ||
| return fmt.Errorf("%v\n%v", specerror.NewError(specerror.PrestartHooksInvoke, fmt.Errorf("The prestart hooks MUST be invoked by the runtime"), rspec.Version), specerror.NewError(specerror.ProcImplement, fmt.Errorf("The runtime MUST run the user-specified program, as specified by `process`"), rspec.Version)) | ||
| } | ||
| switch string(outputData) { | ||
| case "pre-start called\n": | ||
| return specerror.NewError(specerror.ProcImplement, fmt.Errorf("The runtime MUST run the user-specified program, as specified by `process`"), rspec.Version) | ||
| case "process called\n": | ||
| return specerror.NewError(specerror.PrestartHooksInvoke, fmt.Errorf("The prestart hooks MUST be invoked by the runtime"), rspec.Version) | ||
| case "pre-start called\nprocess called\n": | ||
| return nil | ||
| case "process called\npre-start called\n": | ||
| return specerror.NewError(specerror.PrestartTiming, fmt.Errorf("Pre-start hooks MUST be called before the user-specified program command is executed"), rspec.Version) | ||
| default: | ||
| return fmt.Errorf("Unsupported output information: %v", string(outputData)) | ||
| } | ||
| }, | ||
| } | ||
|
|
||
| err := util.RuntimeLifecycleValidate(g, config) | ||
| if err != nil { | ||
| diagnostic := map[string]string{ | ||
| "error": err.Error(), | ||
| } | ||
| if e, ok := err.(*exec.ExitError); ok { | ||
| if len(e.Stderr) > 0 { | ||
| diagnostic["stderr"] = string(e.Stderr) | ||
| } | ||
| } | ||
| t.YAML(diagnostic) | ||
| } | ||
|
|
||
| t.AutoPlan() | ||
| } | ||
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 always got it in 'runc'!