X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/3e1c43866e5b523c3f1d273c25942ad56dc66d3f..516685e09227ab64c2d4f7fd04d4b60a75fc5d0f:/services/crunch-run/crunchrun_test.go diff --git a/services/crunch-run/crunchrun_test.go b/services/crunch-run/crunchrun_test.go index c76682f1c6..0df048cc8b 100644 --- a/services/crunch-run/crunchrun_test.go +++ b/services/crunch-run/crunchrun_test.go @@ -47,6 +47,7 @@ var _ = Suite(&TestSuite{}) type TestSuite struct { client *arvados.Client docker *TestDockerClient + runner *ContainerRunner } func (s *TestSuite) SetUpTest(c *C) { @@ -103,6 +104,7 @@ type TestDockerClient struct { api *ArvTestClient realTemp string calledWait bool + ctrExited bool } func NewTestDockerClient() *TestDockerClient { @@ -176,6 +178,17 @@ func (t *TestDockerClient) ContainerWait(ctx context.Context, container string, return body, err } +func (t *TestDockerClient) ContainerInspect(ctx context.Context, id string) (c dockertypes.ContainerJSON, err error) { + c.ContainerJSONBase = &dockertypes.ContainerJSONBase{} + c.ID = "abcde" + if t.ctrExited { + c.State = &dockertypes.ContainerState{Status: "exited", Dead: true} + } else { + c.State = &dockertypes.ContainerState{Status: "running", Pid: 1234, Running: true} + } + return +} + func (t *TestDockerClient) ImageInspectWithRaw(ctx context.Context, image string) (dockertypes.ImageInspect, []byte, error) { if t.exitCode == 2 { return dockertypes.ImageInspect{}, nil, fmt.Errorf("Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?") @@ -230,6 +243,7 @@ func (client *ArvTestClient) Create(resourceType string, mt := parameters["collection"].(arvadosclient.Dict)["manifest_text"].(string) outmap := output.(*arvados.Collection) outmap.PortableDataHash = fmt.Sprintf("%x+%d", md5.Sum([]byte(mt)), len(mt)) + outmap.UUID = fmt.Sprintf("zzzzz-4zz18-%15.15x", md5.Sum([]byte(mt))) } return nil @@ -316,6 +330,10 @@ func (client *ArvTestClient) Update(resourceType string, uuid string, parameters if parameters["container"].(arvadosclient.Dict)["state"] == "Running" { client.WasSetRunning = true } + } else if resourceType == "collections" { + mt := parameters["collection"].(arvadosclient.Dict)["manifest_text"].(string) + output.(*arvados.Collection).UUID = uuid + output.(*arvados.Collection).PortableDataHash = fmt.Sprintf("%x", md5.Sum([]byte(mt))) } return nil } @@ -357,6 +375,10 @@ call: return nil } +func (client *KeepTestClient) LocalLocator(locator string) (string, error) { + return locator, nil +} + func (client *KeepTestClient) PutB(buf []byte) (string, int, error) { client.Content = buf return fmt.Sprintf("%x+%d", md5.Sum(buf), len(buf)), len(buf), nil @@ -425,6 +447,10 @@ func (s *TestSuite) TestLoadImage(c *C) { cr, err := NewContainerRunner(s.client, &ArvTestClient{}, kc, s.docker, "zzzzz-zzzzz-zzzzzzzzzzzzzzz") c.Assert(err, IsNil) + cr.MkArvClient = func(token string) (IArvadosClient, IKeepClient, error) { + return &ArvTestClient{}, kc, nil + } + _, err = cr.Docker.ImageRemove(nil, hwImageId, dockertypes.ImageRemoveOptions{}) c.Check(err, IsNil) @@ -470,6 +496,9 @@ func (ArvErrorTestClient) Create(resourceType string, } func (ArvErrorTestClient) Call(method, resourceType, uuid, action string, parameters arvadosclient.Dict, output interface{}) error { + if method == "GET" && resourceType == "containers" && action == "auth" { + return nil + } return errors.New("ArvError") } @@ -502,6 +531,10 @@ func (*KeepErrorTestClient) PutB(buf []byte) (string, int, error) { return "", 0, errors.New("KeepError") } +func (*KeepErrorTestClient) LocalLocator(string) (string, error) { + return "", errors.New("KeepError") +} + type KeepReadErrorTestClient struct { KeepTestClient } @@ -530,9 +563,13 @@ func (s *TestSuite) TestLoadImageArvError(c *C) { // (1) Arvados error kc := &KeepTestClient{} defer kc.Close() - cr, err := NewContainerRunner(s.client, ArvErrorTestClient{}, kc, nil, "zzzzz-zzzzz-zzzzzzzzzzzzzzz") + cr, err := NewContainerRunner(s.client, &ArvErrorTestClient{}, kc, nil, "zzzzz-zzzzz-zzzzzzzzzzzzzzz") c.Assert(err, IsNil) + cr.Container.ContainerImage = hwPDH + cr.MkArvClient = func(token string) (IArvadosClient, IKeepClient, error) { + return &ArvErrorTestClient{}, &KeepTestClient{}, nil + } err = cr.LoadImage() c.Check(err.Error(), Equals, "While getting container image collection: ArvError") @@ -540,9 +577,13 @@ func (s *TestSuite) TestLoadImageArvError(c *C) { func (s *TestSuite) TestLoadImageKeepError(c *C) { // (2) Keep error - cr, err := NewContainerRunner(s.client, &ArvTestClient{}, &KeepErrorTestClient{}, s.docker, "zzzzz-zzzzz-zzzzzzzzzzzzzzz") + kc := &KeepErrorTestClient{} + cr, err := NewContainerRunner(s.client, &ArvTestClient{}, kc, s.docker, "zzzzz-zzzzz-zzzzzzzzzzzzzzz") c.Assert(err, IsNil) cr.Container.ContainerImage = hwPDH + cr.MkArvClient = func(token string) (IArvadosClient, IKeepClient, error) { + return &ArvTestClient{}, kc, nil + } err = cr.LoadImage() c.Assert(err, NotNil) @@ -551,9 +592,13 @@ func (s *TestSuite) TestLoadImageKeepError(c *C) { func (s *TestSuite) TestLoadImageCollectionError(c *C) { // (3) Collection doesn't contain image - cr, err := NewContainerRunner(s.client, &ArvTestClient{}, &KeepReadErrorTestClient{}, nil, "zzzzz-zzzzz-zzzzzzzzzzzzzzz") + kc := &KeepReadErrorTestClient{} + cr, err := NewContainerRunner(s.client, &ArvTestClient{}, kc, nil, "zzzzz-zzzzz-zzzzzzzzzzzzzzz") c.Assert(err, IsNil) cr.Container.ContainerImage = otherPDH + cr.MkArvClient = func(token string) (IArvadosClient, IKeepClient, error) { + return &ArvTestClient{}, kc, nil + } err = cr.LoadImage() c.Check(err.Error(), Equals, "First file in the container image collection does not end in .tar") @@ -561,9 +606,13 @@ func (s *TestSuite) TestLoadImageCollectionError(c *C) { func (s *TestSuite) TestLoadImageKeepReadError(c *C) { // (4) Collection doesn't contain image - cr, err := NewContainerRunner(s.client, &ArvTestClient{}, &KeepReadErrorTestClient{}, s.docker, "zzzzz-zzzzz-zzzzzzzzzzzzzzz") + kc := &KeepReadErrorTestClient{} + cr, err := NewContainerRunner(s.client, &ArvTestClient{}, kc, s.docker, "zzzzz-zzzzz-zzzzzzzzzzzzzzz") c.Assert(err, IsNil) cr.Container.ContainerImage = hwPDH + cr.MkArvClient = func(token string) (IArvadosClient, IKeepClient, error) { + return &ArvTestClient{}, kc, nil + } err = cr.LoadImage() c.Check(err, NotNil) @@ -611,6 +660,10 @@ func (s *TestSuite) TestRunContainer(c *C) { cr, err := NewContainerRunner(s.client, &ArvTestClient{}, kc, s.docker, "zzzzz-zzzzz-zzzzzzzzzzzzzzz") c.Assert(err, IsNil) + cr.MkArvClient = func(token string) (IArvadosClient, IKeepClient, error) { + return &ArvTestClient{}, kc, nil + } + var logs TestLogs cr.NewLogWriter = logs.NewTestLoggingWriter cr.Container.ContainerImage = hwPDH @@ -731,7 +784,9 @@ func (s *TestSuite) fullRunHelper(c *C, record string, extraMounts []string, exi defer kc.Close() cr, err = NewContainerRunner(s.client, api, kc, s.docker, "zzzzz-zzzzz-zzzzzzzzzzzzzzz") c.Assert(err, IsNil) + s.runner = cr cr.statInterval = 100 * time.Millisecond + cr.containerWatchdogInterval = time.Second am := &ArvMountCmdLine{} cr.RunArvMount = am.ArvMountTest @@ -752,8 +807,8 @@ func (s *TestSuite) fullRunHelper(c *C, record string, extraMounts []string, exi } return d, err } - cr.MkArvClient = func(token string) (IArvadosClient, error) { - return &ArvTestClient{secretMounts: secretMounts}, nil + cr.MkArvClient = func(token string) (IArvadosClient, IKeepClient, error) { + return &ArvTestClient{secretMounts: secretMounts}, &KeepTestClient{}, nil } if extraMounts != nil && len(extraMounts) > 0 { @@ -793,7 +848,7 @@ func (s *TestSuite) TestFullRunHello(c *C) { "mounts": {"/tmp": {"kind": "tmp"} }, "output_path": "/tmp", "priority": 1, - "runtime_constraints": {} + "runtime_constraints": {} }`, nil, 0, func(t *TestDockerClient) { t.logWriter.Write(dockerLog(1, "hello world\n")) t.logWriter.Close() @@ -805,6 +860,44 @@ func (s *TestSuite) TestFullRunHello(c *C) { } +func (s *TestSuite) TestRunTimeExceeded(c *C) { + api, _, _ := s.fullRunHelper(c, `{ + "command": ["sleep", "3"], + "container_image": "d4ab34d3d4f8a72f5c4973051ae69fab+122", + "cwd": ".", + "environment": {}, + "mounts": {"/tmp": {"kind": "tmp"} }, + "output_path": "/tmp", + "priority": 1, + "runtime_constraints": {}, + "scheduling_parameters":{"max_run_time": 1} +}`, nil, 0, func(t *TestDockerClient) { + time.Sleep(3 * time.Second) + t.logWriter.Close() + }) + + c.Check(api.CalledWith("container.state", "Cancelled"), NotNil) + c.Check(api.Logs["crunch-run"].String(), Matches, "(?ms).*maximum run time exceeded.*") +} + +func (s *TestSuite) TestContainerWaitFails(c *C) { + api, _, _ := s.fullRunHelper(c, `{ + "command": ["sleep", "3"], + "container_image": "d4ab34d3d4f8a72f5c4973051ae69fab+122", + "cwd": ".", + "mounts": {"/tmp": {"kind": "tmp"} }, + "output_path": "/tmp", + "priority": 1 +}`, nil, 0, func(t *TestDockerClient) { + t.ctrExited = true + time.Sleep(10 * time.Second) + t.logWriter.Close() + }) + + c.Check(api.CalledWith("container.state", "Cancelled"), NotNil) + c.Check(api.Logs["crunch-run"].String(), Matches, "(?ms).*Container is not running.*") +} + func (s *TestSuite) TestCrunchstat(c *C) { api, _, _ := s.fullRunHelper(c, `{ "command": ["sleep", "1"], @@ -1011,8 +1104,8 @@ func (s *TestSuite) testStopContainer(c *C, setup func(cr *ContainerRunner)) { cr, err := NewContainerRunner(s.client, api, kc, s.docker, "zzzzz-zzzzz-zzzzzzzzzzzzzzz") c.Assert(err, IsNil) cr.RunArvMount = func([]string, string) (*exec.Cmd, error) { return nil, nil } - cr.MkArvClient = func(token string) (IArvadosClient, error) { - return &ArvTestClient{}, nil + cr.MkArvClient = func(token string) (IArvadosClient, IKeepClient, error) { + return &ArvTestClient{}, &KeepTestClient{}, nil } setup(cr) @@ -1122,7 +1215,7 @@ func (s *TestSuite) TestSetupMounts(c *C) { cr.ArvMountPoint = "" cr.Container.Mounts = make(map[string]arvados.Mount) cr.Container.Mounts["/tmp"] = arvados.Mount{Kind: "tmp"} - cr.OutputPath = "/tmp" + cr.Container.OutputPath = "/tmp" cr.statInterval = 5 * time.Second err := cr.SetupMounts() c.Check(err, IsNil) @@ -1141,7 +1234,7 @@ func (s *TestSuite) TestSetupMounts(c *C) { cr.Container.Mounts = make(map[string]arvados.Mount) cr.Container.Mounts["/out"] = arvados.Mount{Kind: "tmp"} cr.Container.Mounts["/tmp"] = arvados.Mount{Kind: "tmp"} - cr.OutputPath = "/out" + cr.Container.OutputPath = "/out" err := cr.SetupMounts() c.Check(err, IsNil) @@ -1159,7 +1252,7 @@ func (s *TestSuite) TestSetupMounts(c *C) { cr.ArvMountPoint = "" cr.Container.Mounts = make(map[string]arvados.Mount) cr.Container.Mounts["/tmp"] = arvados.Mount{Kind: "tmp"} - cr.OutputPath = "/tmp" + cr.Container.OutputPath = "/tmp" apiflag := true cr.Container.RuntimeConstraints.API = &apiflag @@ -1183,7 +1276,7 @@ func (s *TestSuite) TestSetupMounts(c *C) { cr.Container.Mounts = map[string]arvados.Mount{ "/keeptmp": {Kind: "collection", Writable: true}, } - cr.OutputPath = "/keeptmp" + cr.Container.OutputPath = "/keeptmp" os.MkdirAll(realTemp+"/keep1/tmp0", os.ModePerm) @@ -1205,7 +1298,7 @@ func (s *TestSuite) TestSetupMounts(c *C) { "/keepinp": {Kind: "collection", PortableDataHash: "59389a8f9ee9d399be35462a0f92541c+53"}, "/keepout": {Kind: "collection", Writable: true}, } - cr.OutputPath = "/keepout" + cr.Container.OutputPath = "/keepout" os.MkdirAll(realTemp+"/keep1/by_id/59389a8f9ee9d399be35462a0f92541c+53", os.ModePerm) os.MkdirAll(realTemp+"/keep1/tmp0", os.ModePerm) @@ -1231,7 +1324,7 @@ func (s *TestSuite) TestSetupMounts(c *C) { "/keepinp": {Kind: "collection", PortableDataHash: "59389a8f9ee9d399be35462a0f92541c+53"}, "/keepout": {Kind: "collection", Writable: true}, } - cr.OutputPath = "/keepout" + cr.Container.OutputPath = "/keepout" os.MkdirAll(realTemp+"/keep1/by_id/59389a8f9ee9d399be35462a0f92541c+53", os.ModePerm) os.MkdirAll(realTemp+"/keep1/tmp0", os.ModePerm) @@ -1312,7 +1405,7 @@ func (s *TestSuite) TestSetupMounts(c *C) { "/tmp": {Kind: "tmp"}, "/tmp/foo": {Kind: "collection"}, } - cr.OutputPath = "/tmp" + cr.Container.OutputPath = "/tmp" os.MkdirAll(realTemp+"/keep1/tmp0", os.ModePerm) @@ -1342,7 +1435,7 @@ func (s *TestSuite) TestSetupMounts(c *C) { Path: "baz", Writable: true}, } - cr.OutputPath = "/tmp" + cr.Container.OutputPath = "/tmp" os.MkdirAll(realTemp+"/keep1/by_id/59389a8f9ee9d399be35462a0f92541c+53", os.ModePerm) os.MkdirAll(realTemp+"/keep1/by_id/59389a8f9ee9d399be35462a0f92541d+53/baz", os.ModePerm) @@ -1371,7 +1464,7 @@ func (s *TestSuite) TestSetupMounts(c *C) { "/tmp": {Kind: "tmp"}, "/tmp/foo": {Kind: "tmp"}, } - cr.OutputPath = "/tmp" + cr.Container.OutputPath = "/tmp" err := cr.SetupMounts() c.Check(err, NotNil) @@ -1419,7 +1512,7 @@ func (s *TestSuite) TestSetupMounts(c *C) { Path: "/", }, } - cr.OutputPath = "/tmp" + cr.Container.OutputPath = "/tmp" err := cr.SetupMounts() c.Check(err, IsNil) @@ -1495,8 +1588,8 @@ func (s *TestSuite) stdoutErrorRunHelper(c *C, record string, fn func(t *TestDoc c.Assert(err, IsNil) am := &ArvMountCmdLine{} cr.RunArvMount = am.ArvMountTest - cr.MkArvClient = func(token string) (IArvadosClient, error) { - return &ArvTestClient{}, nil + cr.MkArvClient = func(token string) (IArvadosClient, IKeepClient, error) { + return &ArvTestClient{}, &KeepTestClient{}, nil } err = cr.Run() @@ -2047,3 +2140,49 @@ func (s *TestSuite) TestSecretTextMountPoint(c *C) { c.Check(api.CalledWith("collection.manifest_text", ". 34819d7beeabb9260a5c854bc85b3e44+10 0:10:secret.conf\n"), IsNil) c.Check(api.CalledWith("collection.manifest_text", ""), NotNil) } + +type FakeProcess struct { + cmdLine []string +} + +func (fp FakeProcess) CmdlineSlice() ([]string, error) { + return fp.cmdLine, nil +} + +func (s *TestSuite) helpCheckContainerd(c *C, lp func() ([]PsProcess, error)) error { + kc := &KeepTestClient{} + defer kc.Close() + cr, err := NewContainerRunner(s.client, &ArvTestClient{callraw: true}, kc, s.docker, "zzzzz-zzzzz-zzzzzzzzzzzzzzz") + cr.checkContainerd = time.Duration(100 * time.Millisecond) + c.Assert(err, IsNil) + cr.ListProcesses = lp + + s.docker.fn = func(t *TestDockerClient) { + time.Sleep(1 * time.Second) + t.logWriter.Close() + } + + err = cr.CreateContainer() + c.Check(err, IsNil) + + err = cr.StartContainer() + c.Check(err, IsNil) + + err = cr.WaitFinish() + return err + +} + +func (s *TestSuite) TestCheckContainerdPresent(c *C) { + err := s.helpCheckContainerd(c, func() ([]PsProcess, error) { + return []PsProcess{FakeProcess{[]string{"docker-containerd"}}}, nil + }) + c.Check(err, IsNil) +} + +func (s *TestSuite) TestCheckContainerdMissing(c *C) { + err := s.helpCheckContainerd(c, func() ([]PsProcess, error) { + return []PsProcess{FakeProcess{[]string{"abc"}}}, nil + }) + c.Check(err, ErrorMatches, `'containerd' not found in process list.`) +}