Skip to content

Commit 59053a6

Browse files
authored
Merge pull request #558 from q384566678/lifecycle-validation
add lifecycle validation
2 parents c785e93 + 09ddc02 commit 59053a6

File tree

3 files changed

+292
-0
lines changed

3 files changed

+292
-0
lines changed

validation/poststart.go

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"io/ioutil"
6+
"os"
7+
"os/exec"
8+
"path/filepath"
9+
"strings"
10+
"time"
11+
12+
tap "github.com/mndrix/tap-go"
13+
rspec "github.com/opencontainers/runtime-spec/specs-go"
14+
"github.com/opencontainers/runtime-tools/specerror"
15+
"github.com/opencontainers/runtime-tools/validation/util"
16+
uuid "github.com/satori/go.uuid"
17+
)
18+
19+
func main() {
20+
t := tap.New()
21+
t.Header(0)
22+
23+
g := util.GetDefaultGenerator()
24+
25+
var output string
26+
config := util.LifecycleConfig{
27+
Actions: util.LifecycleActionCreate | util.LifecycleActionStart | util.LifecycleActionDelete,
28+
PreCreate: func(r *util.Runtime) error {
29+
r.SetID(uuid.NewV4().String())
30+
31+
output = filepath.Join(r.BundleDir, g.Spec().Root.Path, "output")
32+
poststart := rspec.Hook{
33+
Path: fmt.Sprintf("%s/%s/bin/sh", r.BundleDir, g.Spec().Root.Path),
34+
Args: []string{
35+
"sh", "-c", fmt.Sprintf("echo 'post-start called' >> %s", output),
36+
},
37+
}
38+
39+
g.AddPostStartHook(poststart)
40+
g.SetProcessArgs([]string{"sh", "-c", fmt.Sprintf("echo 'process called' >> %s", "/output")})
41+
r.SetConfig(g)
42+
return nil
43+
},
44+
PostCreate: func(r *util.Runtime) error {
45+
outputData, err := ioutil.ReadFile(output)
46+
if err == nil {
47+
if strings.Contains(string(outputData), "post-start called") {
48+
return specerror.NewError(specerror.PoststartTiming, fmt.Errorf("The post-start hooks MUST be called before the `start` operation returns"), rspec.Version)
49+
} else if strings.Contains(string(outputData), "process called") {
50+
return specerror.NewError(specerror.ProcNotRunAtResRequest, fmt.Errorf("The user-specified program (from process) MUST NOT be run at this time"), rspec.Version)
51+
}
52+
return fmt.Errorf("File %v should not exist", output)
53+
}
54+
return nil
55+
},
56+
PreDelete: func(r *util.Runtime) error {
57+
util.WaitingForStatus(*r, util.LifecycleStatusStopped, time.Second*10, time.Second)
58+
outputData, err := ioutil.ReadFile(output)
59+
if err != nil {
60+
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))
61+
}
62+
switch string(outputData) {
63+
case "post-start called\n":
64+
return specerror.NewError(specerror.ProcImplement, fmt.Errorf("The runtime MUST run the user-specified program, as specified by `process`"), rspec.Version)
65+
case "process called\n":
66+
fmt.Fprintln(os.Stderr, "WARNING: The poststart hook invoke fails")
67+
return nil
68+
case "post-start called\nprocess called\n":
69+
return specerror.NewError(specerror.PoststartTiming, fmt.Errorf("The post-start hooks MUST be called after the user-specified process is executed"), rspec.Version)
70+
case "process called\npost-start called\n":
71+
return nil
72+
default:
73+
return fmt.Errorf("Unsupported output information: %v", string(outputData))
74+
}
75+
},
76+
}
77+
78+
err := util.RuntimeLifecycleValidate(g, config)
79+
if err != nil {
80+
diagnostic := map[string]string{
81+
"error": err.Error(),
82+
}
83+
if e, ok := err.(*exec.ExitError); ok {
84+
if len(e.Stderr) > 0 {
85+
diagnostic["stderr"] = string(e.Stderr)
86+
}
87+
}
88+
t.YAML(diagnostic)
89+
}
90+
91+
t.AutoPlan()
92+
}

validation/poststop.go

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
package main
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"io/ioutil"
7+
"os"
8+
"os/exec"
9+
"path/filepath"
10+
"strings"
11+
"time"
12+
13+
tap "github.com/mndrix/tap-go"
14+
rspec "github.com/opencontainers/runtime-spec/specs-go"
15+
"github.com/opencontainers/runtime-tools/specerror"
16+
"github.com/opencontainers/runtime-tools/validation/util"
17+
uuid "github.com/satori/go.uuid"
18+
)
19+
20+
func main() {
21+
t := tap.New()
22+
t.Header(0)
23+
24+
g := util.GetDefaultGenerator()
25+
26+
var output string
27+
config := util.LifecycleConfig{
28+
Actions: util.LifecycleActionCreate | util.LifecycleActionStart | util.LifecycleActionDelete,
29+
PreCreate: func(r *util.Runtime) error {
30+
r.SetID(uuid.NewV4().String())
31+
32+
output = filepath.Join(r.BundleDir, g.Spec().Root.Path, "output")
33+
poststop := rspec.Hook{
34+
Path: fmt.Sprintf("%s/%s/bin/sh", r.BundleDir, g.Spec().Root.Path),
35+
Args: []string{
36+
"sh", "-c", fmt.Sprintf("echo 'post-stop called' >> %s", output),
37+
},
38+
}
39+
40+
g.AddPostStopHook(poststop)
41+
g.SetProcessArgs([]string{"sh", "-c", fmt.Sprintf("echo 'process called' >> %s", "/output")})
42+
r.SetConfig(g)
43+
return nil
44+
},
45+
PostCreate: func(r *util.Runtime) error {
46+
outputData, err := ioutil.ReadFile(output)
47+
if err == nil {
48+
if strings.Contains(string(outputData), "post-stop called") {
49+
return specerror.NewError(specerror.PoststopTiming, fmt.Errorf("The post-stop hooks MUST be called after the container is deleted"), rspec.Version)
50+
} else if strings.Contains(string(outputData), "process called") {
51+
return specerror.NewError(specerror.ProcNotRunAtResRequest, fmt.Errorf("The user-specified program (from process) MUST NOT be run at this time"), rspec.Version)
52+
}
53+
return fmt.Errorf("File %v should not exist", output)
54+
}
55+
return nil
56+
},
57+
PreDelete: func(r *util.Runtime) error {
58+
util.WaitingForStatus(*r, util.LifecycleStatusStopped, time.Second*10, time.Second)
59+
outputData, err := ioutil.ReadFile(output)
60+
if err != nil {
61+
return specerror.NewError(specerror.ProcImplement, fmt.Errorf("The runtime MUST run the user-specified program, as specified by `process`"), rspec.Version)
62+
}
63+
switch string(outputData) {
64+
case "post-stop called\n":
65+
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))
66+
case "process called\n":
67+
return nil
68+
case "post-stop called\nprocess called\n", "process called\npost-stop called\n":
69+
return specerror.NewError(specerror.PoststopTiming, fmt.Errorf("The post-stop hooks MUST be called after the container is deleted"), rspec.Version)
70+
default:
71+
return fmt.Errorf("Unsupported output information: %v", string(outputData))
72+
}
73+
},
74+
PostDelete: func(r *util.Runtime) error {
75+
outputData, err := ioutil.ReadFile(output)
76+
if err != nil {
77+
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))
78+
}
79+
switch string(outputData) {
80+
case "post-stop called\n":
81+
return specerror.NewError(specerror.ProcImplement, fmt.Errorf("The runtime MUST run the user-specified program, as specified by `process`"), rspec.Version)
82+
case "process called\n":
83+
fmt.Fprintln(os.Stderr, "WARNING: The poststop hook invoke fails")
84+
return nil
85+
case "post-stop called\nprocess called\n":
86+
return errors.New("The Post-stop should called after the user-specified program command is executed")
87+
case "process called\npost-stop called\n":
88+
return nil
89+
default:
90+
return fmt.Errorf("Unsupported output information: %v", string(outputData))
91+
}
92+
},
93+
}
94+
95+
err := util.RuntimeLifecycleValidate(g, config)
96+
if err != nil {
97+
diagnostic := map[string]string{
98+
"error": err.Error(),
99+
}
100+
if e, ok := err.(*exec.ExitError); ok {
101+
if len(e.Stderr) > 0 {
102+
diagnostic["stderr"] = string(e.Stderr)
103+
}
104+
}
105+
t.YAML(diagnostic)
106+
}
107+
108+
t.AutoPlan()
109+
}

validation/prestart.go

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"io/ioutil"
6+
"os/exec"
7+
"path/filepath"
8+
"strings"
9+
"time"
10+
11+
tap "github.com/mndrix/tap-go"
12+
rspec "github.com/opencontainers/runtime-spec/specs-go"
13+
"github.com/opencontainers/runtime-tools/specerror"
14+
"github.com/opencontainers/runtime-tools/validation/util"
15+
uuid "github.com/satori/go.uuid"
16+
)
17+
18+
func main() {
19+
t := tap.New()
20+
t.Header(0)
21+
22+
g := util.GetDefaultGenerator()
23+
24+
var output string
25+
config := util.LifecycleConfig{
26+
Actions: util.LifecycleActionCreate | util.LifecycleActionStart | util.LifecycleActionDelete,
27+
PreCreate: func(r *util.Runtime) error {
28+
r.SetID(uuid.NewV4().String())
29+
30+
output = filepath.Join(r.BundleDir, g.Spec().Root.Path, "output")
31+
prestart := rspec.Hook{
32+
Path: fmt.Sprintf("%s/%s/bin/sh", r.BundleDir, g.Spec().Root.Path),
33+
Args: []string{
34+
"sh", "-c", fmt.Sprintf("echo 'pre-start called' >> %s", output),
35+
},
36+
}
37+
38+
g.AddPreStartHook(prestart)
39+
g.SetProcessArgs([]string{"sh", "-c", fmt.Sprintf("echo 'process called' >> %s", "/output")})
40+
r.SetConfig(g)
41+
return nil
42+
},
43+
PostCreate: func(r *util.Runtime) error {
44+
outputData, err := ioutil.ReadFile(output)
45+
if err == nil {
46+
if strings.Contains(string(outputData), "pre-start called") {
47+
return specerror.NewError(specerror.PrestartTiming, fmt.Errorf("Pre-start hooks MUST be called after the `start` operation is called"), rspec.Version)
48+
} else if strings.Contains(string(outputData), "process called") {
49+
return specerror.NewError(specerror.ProcNotRunAtResRequest, fmt.Errorf("The user-specified program (from process) MUST NOT be run at this time"), rspec.Version)
50+
}
51+
52+
return fmt.Errorf("File %v should not exist", output)
53+
}
54+
return nil
55+
},
56+
PreDelete: func(r *util.Runtime) error {
57+
util.WaitingForStatus(*r, util.LifecycleStatusStopped, time.Second*10, time.Second)
58+
outputData, err := ioutil.ReadFile(output)
59+
if err != nil {
60+
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))
61+
}
62+
switch string(outputData) {
63+
case "pre-start called\n":
64+
return specerror.NewError(specerror.ProcImplement, fmt.Errorf("The runtime MUST run the user-specified program, as specified by `process`"), rspec.Version)
65+
case "process called\n":
66+
return specerror.NewError(specerror.PrestartHooksInvoke, fmt.Errorf("The prestart hooks MUST be invoked by the runtime"), rspec.Version)
67+
case "pre-start called\nprocess called\n":
68+
return nil
69+
case "process called\npre-start called\n":
70+
return specerror.NewError(specerror.PrestartTiming, fmt.Errorf("Pre-start hooks MUST be called before the user-specified program command is executed"), rspec.Version)
71+
default:
72+
return fmt.Errorf("Unsupported output information: %v", string(outputData))
73+
}
74+
},
75+
}
76+
77+
err := util.RuntimeLifecycleValidate(g, config)
78+
if err != nil {
79+
diagnostic := map[string]string{
80+
"error": err.Error(),
81+
}
82+
if e, ok := err.(*exec.ExitError); ok {
83+
if len(e.Stderr) > 0 {
84+
diagnostic["stderr"] = string(e.Stderr)
85+
}
86+
}
87+
t.YAML(diagnostic)
88+
}
89+
90+
t.AutoPlan()
91+
}

0 commit comments

Comments
 (0)