Skip to content

Commit 9ee5be2

Browse files
author
Ma Shimiao
committed
split runtimevalidate into inside and outside validaiton
Signed-off-by: Ma Shimiao <[email protected]>
1 parent bbf9886 commit 9ee5be2

File tree

2 files changed

+176
-33
lines changed

2 files changed

+176
-33
lines changed

Makefile

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ $(RUNTIME_TOOLS_LINK):
3939
localvalidation:
4040
RUNTIME=$(RUNTIME) go test -tags "$(BUILDTAGS)" ${TESTFLAGS} -v github.com/opencontainers/runtime-tools/validation
4141

42-
4342
.PHONY: test .gofmt .govet .golint
4443

4544
test: .gofmt .govet .golint

validation/validation_test.go

Lines changed: 176 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
11
package validation
22

33
import (
4+
"encoding/json"
45
"fmt"
56
"io/ioutil"
67
"os"
78
"os/exec"
89
"path/filepath"
10+
"strings"
911
"testing"
1012

13+
"github.com/hashicorp/go-multierror"
14+
"github.com/mndrix/tap-go"
1115
"github.com/mrunalp/fileutils"
16+
rspec "github.com/opencontainers/runtime-spec/specs-go"
1217
"github.com/opencontainers/runtime-tools/generate"
1318
"github.com/satori/go.uuid"
1419
)
@@ -17,51 +22,93 @@ var (
1722
runtime = "runc"
1823
)
1924

25+
type validation struct {
26+
test func(string, string, *rspec.Spec) error
27+
description string
28+
}
29+
2030
func init() {
2131
runtime = os.Getenv("RUNTIME")
2232
}
2333

24-
func runtimeValidate(runtime string, g *generate.Generator) error {
34+
func TestValidateRuntimeInside(t *testing.T) {
35+
g, err := getDefaultGenerator()
36+
if err != nil {
37+
t.Errorf("%s failed validation: %v", runtime, err)
38+
}
39+
g.SetProcessArgs([]string{"/runtimetest"})
40+
41+
if err := runtimeInsideValidate(runtime, g); err != nil {
42+
t.Errorf("%s failed validation: %v", runtime, err)
43+
}
44+
}
45+
46+
func TestValidateRuntimeOutside(t *testing.T) {
47+
g, err := getDefaultGenerator()
48+
if err != nil {
49+
t.Errorf("%s failed validation: %v", runtime, err)
50+
}
51+
g.SetProcessArgs([]string{"sleep", "50"})
52+
53+
if err := runtimeOutsideValidate(runtime, g); err != nil {
54+
t.Errorf("%s failed validation: %v", runtime, err)
55+
}
56+
}
57+
58+
func runtimeInsideValidate(runtime string, g *generate.Generator) error {
2559
// Find the runtime binary in the PATH
2660
runtimePath, err := exec.LookPath(runtime)
2761
if err != nil {
2862
return err
2963
}
3064

31-
// Setup a temporary test directory
32-
tmpDir, err := ioutil.TempDir("", "ocitest")
65+
bundleDir, rootfsDir, err := prepareBundle(g)
3366
if err != nil {
3467
return err
3568
}
36-
defer os.RemoveAll(tmpDir)
69+
defer os.RemoveAll(bundleDir)
3770

38-
// Create bundle directory for the test container
39-
bundleDir := tmpDir + "/busybox"
40-
if err := os.MkdirAll(bundleDir, 0755); err != nil {
71+
// Copy the runtimetest binary to the rootfs
72+
err = fileutils.CopyFile("../runtimetest", filepath.Join(rootfsDir, "runtimetest"))
73+
if err != nil {
4174
return err
4275
}
4376

44-
// Untar the root fs
45-
untarCmd := exec.Command("tar", "-xf", "../rootfs.tar.gz", "-C", bundleDir)
46-
output, err := untarCmd.CombinedOutput()
47-
if err != nil {
48-
fmt.Println(string(output))
77+
// TODO: Use a library to split run into create/start
78+
// Launch the OCI runtime
79+
containerID := uuid.NewV4()
80+
runtimeCmd := exec.Command(runtimePath, "run", containerID.String())
81+
runtimeCmd.Dir = bundleDir
82+
runtimeCmd.Stdin = os.Stdin
83+
runtimeCmd.Stdout = os.Stdout
84+
runtimeCmd.Stderr = os.Stderr
85+
if err = runtimeCmd.Run(); err != nil {
4986
return err
5087
}
5188

52-
// Copy the runtimetest binary to the rootfs
53-
err = fileutils.CopyFile("../runtimetest", filepath.Join(bundleDir, "runtimetest"))
89+
if err = cleanup(runtimePath, containerID.String()); err != nil {
90+
return err
91+
}
5492

55-
// Generate test configuration
56-
err = g.SaveToFile(filepath.Join(bundleDir, "config.json"), generate.ExportOptions{})
93+
return nil
94+
}
95+
96+
func runtimeOutsideValidate(runtime string, g *generate.Generator) error {
97+
// Find the runtime binary in the PATH
98+
runtimePath, err := exec.LookPath(runtime)
5799
if err != nil {
58100
return err
59101
}
60102

61-
// TODO: Use a library to split run into create/start
103+
bundleDir, _, err := prepareBundle(g)
104+
if err != nil {
105+
return err
106+
}
107+
// defer os.RemoveAll(bundleDir)
108+
62109
// Launch the OCI runtime
63110
containerID := uuid.NewV4()
64-
runtimeCmd := exec.Command(runtimePath, "run", containerID.String())
111+
runtimeCmd := exec.Command(runtimePath, "create", containerID.String())
65112
runtimeCmd.Dir = bundleDir
66113
runtimeCmd.Stdin = os.Stdin
67114
runtimeCmd.Stdout = os.Stdout
@@ -70,29 +117,126 @@ func runtimeValidate(runtime string, g *generate.Generator) error {
70117
return err
71118
}
72119

120+
outsideValidations := []validation{
121+
{
122+
test: validateLabels,
123+
description: "labels",
124+
},
125+
// Add more container outside validation
126+
}
127+
128+
t := tap.New()
129+
t.Header(0)
130+
131+
var validationErrors error
132+
for _, v := range outsideValidations {
133+
err := v.test(runtimePath, containerID.String(), g.Spec())
134+
t.Ok(err == nil, v.description)
135+
if err != nil {
136+
validationErrors = multierror.Append(validationErrors, err)
137+
}
138+
}
139+
t.AutoPlan()
140+
141+
if err = cleanup(runtimePath, containerID.String()); err != nil {
142+
validationErrors = multierror.Append(validationErrors, err)
143+
}
144+
145+
return validationErrors
146+
}
147+
148+
func validateLabels(runtimePath, id string, spec *rspec.Spec) error {
149+
runtimeCmd := exec.Command(runtimePath, "state", id)
150+
output, err := runtimeCmd.Output()
151+
if err != nil {
152+
return err
153+
}
154+
155+
var state rspec.State
156+
if err := json.NewDecoder(strings.NewReader(string(output))).Decode(&state); err != nil {
157+
return err
158+
}
159+
for key, value := range spec.Annotations {
160+
if state.Annotations[key] == value {
161+
continue
162+
}
163+
return fmt.Errorf("Expected annotation %s:%s not set", key, value)
164+
}
73165
return nil
74166
}
75167

76-
func getDefaultGenerator() *generate.Generator {
77-
g := generate.New()
78-
g.SetRootPath(".")
79-
g.SetProcessArgs([]string{"/runtimetest"})
80-
return &g
168+
func cleanup(runtimePath, id string) error {
169+
runtimeCmd := exec.Command(runtimePath, "kill", id, "KILL")
170+
if err := runtimeCmd.Run(); err != nil {
171+
return fmt.Errorf("Failed to kill container %s: %v", id, err)
172+
}
173+
174+
runtimeCmd = exec.Command(runtimePath, "delete", id)
175+
if err := runtimeCmd.Run(); err != nil {
176+
return fmt.Errorf("Failed to kill container %s: %v", id, err)
177+
}
178+
179+
return nil
81180
}
82181

83-
func TestValidateBasic(t *testing.T) {
84-
g := getDefaultGenerator()
182+
func prepareBundle(g *generate.Generator) (string, string, error) {
183+
// Setup a temporary test directory
184+
tmpDir, err := ioutil.TempDir("", "ocitest")
185+
if err != nil {
186+
return "", "", err
187+
}
85188

86-
if err := runtimeValidate(runtime, g); err != nil {
87-
t.Errorf("%s failed validation: %v", runtime, err)
189+
// Create bundle directory for the test container
190+
bundleDir := tmpDir
191+
if err := os.MkdirAll(bundleDir, 0755); err != nil {
192+
return "", "", err
193+
}
194+
195+
// Create rootfs directory for the test container
196+
rootfsDir := bundleDir + "/rootfs"
197+
if err := os.MkdirAll(rootfsDir, 0755); err != nil {
198+
return "", "", err
199+
}
200+
201+
// Untar the root fs
202+
untarCmd := exec.Command("tar", "-xf", "../rootfs.tar.gz", "-C", rootfsDir)
203+
output, err := untarCmd.CombinedOutput()
204+
if err != nil {
205+
fmt.Println(string(output))
206+
return "", "", err
207+
}
208+
209+
// Generate test configuration
210+
err = g.SaveToFile(filepath.Join(bundleDir, "config.json"), generate.ExportOptions{})
211+
if err != nil {
212+
return "", "", err
88213
}
214+
215+
// Copy the configuration file to the rootfs
216+
err = fileutils.CopyFile(filepath.Join(bundleDir, "config.json"), filepath.Join(rootfsDir, "config.json"))
217+
if err != nil {
218+
return "", "", err
219+
}
220+
221+
return bundleDir, rootfsDir, nil
89222
}
90223

91-
func TestValidateSysctls(t *testing.T) {
92-
g := getDefaultGenerator()
93-
g.AddLinuxSysctl("net.ipv4.ip_forward", "1")
224+
func getDefaultGenerator() (*generate.Generator, error) {
225+
// Generate testcase template
226+
generateCmd := exec.Command("oci-runtime-tool", "generate", "--bind=/tmp:/volume/testing:rw", "--cgroups-path=/tmp/testcgroup", "--device-add=c:80:500:/dev/test:fileMode=438", "--disable-oom-kill=true", "--env=testvar=vartest", "--hostname=localvalidation", "--label=testlabel=nonevar", "--linux-cpu-shares=1024", "--output", "/tmp/config.json")
227+
output, err := generateCmd.CombinedOutput()
228+
if err != nil {
229+
fmt.Println(string(output))
230+
return nil, err
231+
}
94232

95-
if err := runtimeValidate(runtime, g); err != nil {
96-
t.Errorf("%s failed validation: %v", runtime, err)
233+
// Get testcase configuration
234+
g, err := generate.NewFromFile("/tmp/config.json")
235+
if err != nil {
236+
return nil, err
97237
}
238+
239+
g.SetRootPath("rootfs")
240+
241+
return &g, nil
98242
}

0 commit comments

Comments
 (0)