Skip to content

Commit 57ed4be

Browse files
arampricejfmyers9
authored andcommitted
List dead job-processes as failed
Previously listed as `stopped` but this only occurs when a bpm job-process dies, or is unexpectedly killed. [finishes #152414698] Signed-off-by: James Myers <jmyers@pivotal.io>
1 parent 46eaf28 commit 57ed4be

File tree

8 files changed

+150
-31
lines changed

8 files changed

+150
-31
lines changed

src/bpm/commands/start.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ package commands
1717

1818
import (
1919
"bpm/config"
20-
"bpm/runc/lifecycle"
20+
"bpm/models"
2121
"fmt"
2222

2323
"github.com/spf13/cobra"
@@ -83,10 +83,10 @@ func start(cmd *cobra.Command, _ []string) error {
8383
}
8484

8585
switch state {
86-
case lifecycle.ContainerStateRunning:
86+
case models.ProcessStateRunning:
8787
logger.Info("process-already-running")
8888
return nil
89-
case lifecycle.ContainerStateStopped:
89+
case models.ProcessStateFailed:
9090
logger.Info("removing-stopped-process")
9191
if err := runcLifecycle.RemoveProcess(bpmCfg); err != nil {
9292
logger.Error("failed-to-cleanup", err)

src/bpm/main_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -781,7 +781,7 @@ var _ = Describe("bpm", func() {
781781
session, err = gexec.Start(command, GinkgoWriter, GinkgoWriter)
782782
Expect(err).ShouldNot(HaveOccurred())
783783
Eventually(session).Should(gexec.Exit(0))
784-
Expect(session.Out).Should(gbytes.Say("stopped"))
784+
Expect(session.Out).Should(gbytes.Say("failed"))
785785
})
786786

787787
It("`bpm start` cleans up the associated container and artifacts and starts it", func() {
@@ -816,7 +816,7 @@ var _ = Describe("bpm", func() {
816816
Expect(err).ShouldNot(HaveOccurred())
817817
Eventually(session).Should(gexec.Exit(0))
818818

819-
Expect(session.Out).Should(gbytes.Say("stopped"))
819+
Expect(session.Out).Should(gbytes.Say("failed"))
820820
})
821821
})
822822
})

src/bpm/models/models.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@
1515

1616
package models
1717

18+
const (
19+
ProcessStateRunning = "running"
20+
ProcessStateFailed = "failed"
21+
)
22+
1823
type Process struct {
1924
Name string
2025
Pid int

src/bpm/presenters/presenters.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,22 @@ import (
2525
"text/tabwriter"
2626
)
2727

28-
func PrintJobs(jobs []models.Process, stdout io.Writer) error {
28+
func PrintJobs(processes []*models.Process, stdout io.Writer) error {
2929
tw := tabwriter.NewWriter(stdout, 0, 0, 1, ' ', 0)
3030

3131
printRow(tw, "Name", "Pid", "Status")
32-
for _, job := range jobs {
33-
name, err := config.Decode(job.Name)
32+
for _, process := range processes {
33+
name, err := config.Decode(process.Name)
3434
if err != nil {
3535
return err
3636
}
37-
printRow(tw, name, strconv.Itoa(job.Pid), job.Status)
37+
38+
pid := "-"
39+
if process.Pid > 0 {
40+
pid = strconv.Itoa(process.Pid)
41+
}
42+
43+
printRow(tw, name, pid, process.Status)
3844
}
3945

4046
return tw.Flush()
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright (C) 2017-Present Pivotal Software, Inc. All rights reserved.
2+
//
3+
// This program and the accompanying materials are made available under
4+
// the terms of the under the Apache License, Version 2.0 (the "License”);
5+
// you may not use this file except in compliance with the License.
6+
//
7+
// You may obtain a copy of the License at
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
// License for the specific language governing permissions and limitations
14+
// under the License.
15+
16+
package presenters_test
17+
18+
import (
19+
. "github.com/onsi/ginkgo"
20+
. "github.com/onsi/gomega"
21+
22+
"testing"
23+
)
24+
25+
func TestPresenters(t *testing.T) {
26+
RegisterFailHandler(Fail)
27+
RunSpecs(t, "Presenters Suite")
28+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Copyright (C) 2017-Present Pivotal Software, Inc. All rights reserved.
2+
//
3+
// This program and the accompanying materials are made available under
4+
// the terms of the under the Apache License, Version 2.0 (the "License”);
5+
// you may not use this file except in compliance with the License.
6+
//
7+
// You may obtain a copy of the License at
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
// License for the specific language governing permissions and limitations
14+
// under the License.
15+
16+
package presenters_test
17+
18+
import (
19+
"bpm/config"
20+
"bpm/models"
21+
"bpm/presenters"
22+
"fmt"
23+
24+
. "github.com/onsi/ginkgo"
25+
. "github.com/onsi/gomega"
26+
"github.com/onsi/gomega/gbytes"
27+
)
28+
29+
var _ = Describe("Presenters", func() {
30+
Describe("PresentJobs", func() {
31+
var (
32+
processes []*models.Process
33+
output *gbytes.Buffer
34+
)
35+
36+
BeforeEach(func() {
37+
processes = []*models.Process{
38+
{Name: config.Encode("job-process-2"), Pid: 23456, Status: "created"},
39+
{Name: config.Encode("job-process-1"), Pid: 34567, Status: "running"},
40+
{Name: config.Encode("job-process-3"), Pid: 0, Status: "failed"},
41+
}
42+
43+
output = gbytes.NewBuffer()
44+
})
45+
46+
It("prints the jobs in a table", func() {
47+
Expect(presenters.PrintJobs(processes, output)).To(Succeed())
48+
Expect(output).Should(gbytes.Say("Name\\s+Pid\\s+Status"))
49+
Expect(output).Should(gbytes.Say(fmt.Sprintf("%s\\s+%d\\s+%s", "job-process-2", 23456, "created")))
50+
Expect(output).Should(gbytes.Say(fmt.Sprintf("%s\\s+%d\\s+%s", "job-process-1", 34567, "running")))
51+
Expect(output).Should(gbytes.Say(fmt.Sprintf("%s\\s+%s\\s+%s", "job-process-3", "-", "failed")))
52+
})
53+
})
54+
})

src/bpm/runc/lifecycle/lifecycle.go

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -165,31 +165,30 @@ func (j *RuncLifecycle) GetProcess(cfg *config.BPMConfig) (*models.Process, erro
165165
return nil, nil
166166
}
167167

168-
return &models.Process{
169-
Name: container.ID,
170-
Pid: container.Pid,
171-
Status: container.Status,
172-
}, nil
168+
return newProcessFromContainerState(
169+
container.ID,
170+
container.Status,
171+
container.Pid,
172+
), nil
173173
}
174174

175175
func (j *RuncLifecycle) OpenShell(cfg *config.BPMConfig, stdin io.Reader, stdout, stderr io.Writer) error {
176176
return j.runcClient.Exec(cfg.ContainerID(true), "/bin/bash", stdin, stdout, stderr)
177177
}
178178

179-
func (j *RuncLifecycle) ListProcesses() ([]models.Process, error) {
179+
func (j *RuncLifecycle) ListProcesses() ([]*models.Process, error) {
180180
containers, err := j.runcClient.ListContainers()
181181
if err != nil {
182182
return nil, err
183183
}
184184

185-
var processes []models.Process
185+
var processes []*models.Process
186186
for _, c := range containers {
187-
process := models.Process{
188-
Name: c.ID,
189-
Pid: c.InitProcessPid,
190-
Status: c.Status,
191-
}
192-
processes = append(processes, process)
187+
processes = append(processes, newProcessFromContainerState(
188+
c.ID,
189+
c.Status,
190+
c.InitProcessPid,
191+
))
193192
}
194193

195194
return processes, nil
@@ -205,7 +204,7 @@ func (j *RuncLifecycle) StopProcess(logger lager.Logger, cfg *config.BPMConfig,
205204
if err != nil {
206205
logger.Error("failed-to-fetch-state", err)
207206
} else {
208-
if state.Status == "stopped" {
207+
if state.Status == ContainerStateStopped {
209208
return nil
210209
}
211210
}
@@ -221,7 +220,7 @@ func (j *RuncLifecycle) StopProcess(logger lager.Logger, cfg *config.BPMConfig,
221220
if err != nil {
222221
logger.Error("failed-to-fetch-state", err)
223222
} else {
224-
if state.Status == "stopped" {
223+
if state.Status == ContainerStateStopped {
225224
return nil
226225
}
227226
}
@@ -246,6 +245,18 @@ func (j *RuncLifecycle) RemoveProcess(cfg *config.BPMConfig) error {
246245
return j.runcClient.DestroyBundle(cfg.BundlePath())
247246
}
248247

248+
func newProcessFromContainerState(id, status string, pid int) *models.Process {
249+
if status == ContainerStateStopped {
250+
status = "failed"
251+
}
252+
253+
return &models.Process{
254+
Name: id,
255+
Pid: pid,
256+
Status: status,
257+
}
258+
}
259+
249260
type commandRunner struct{}
250261

251262
func NewCommandRunner() CommandRunner { return &commandRunner{} }

src/bpm/runc/lifecycle/lifecycle_test.go

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -518,10 +518,10 @@ var _ = Describe("RuncJobLifecycle", func() {
518518
bpmJobs, err := runcLifecycle.ListProcesses()
519519
Expect(err).NotTo(HaveOccurred())
520520

521-
Expect(bpmJobs).To(ConsistOf([]models.Process{
521+
Expect(bpmJobs).To(ConsistOf([]*models.Process{
522522
{Name: "job-process-2", Pid: 23456, Status: "created"},
523523
{Name: "job-process-1", Pid: 34567, Status: "running"},
524-
{Name: "job-process-3", Pid: 0, Status: "stopped"},
524+
{Name: "job-process-3", Pid: 0, Status: "failed"},
525525
}))
526526
})
527527

@@ -542,18 +542,33 @@ var _ = Describe("RuncJobLifecycle", func() {
542542
})
543543

544544
It("fetches the container state and translates it into a job", func() {
545-
job, err := runcLifecycle.GetProcess(bpmCfg)
545+
process, err := runcLifecycle.GetProcess(bpmCfg)
546546
Expect(err).NotTo(HaveOccurred())
547547
Expect(fakeRuncClient.ContainerStateCallCount()).To(Equal(1))
548548
Expect(fakeRuncClient.ContainerStateArgsForCall(0)).To(Equal(expectedContainerID))
549-
Expect(job).NotTo(BeNil())
550-
Expect(*job).To(Equal(models.Process{
549+
Expect(process).To(Equal(&models.Process{
551550
Name: expectedContainerID,
552551
Pid: 1234,
553552
Status: "running",
554553
}))
555554
})
556555

556+
Context("when the container state is stopped", func() {
557+
BeforeEach(func() {
558+
fakeRuncClient.ContainerStateReturns(&specs.State{ID: expectedContainerID, Pid: 0, Status: "stopped"}, nil)
559+
})
560+
561+
It("fetches the container state and translates it into a job", func() {
562+
process, err := runcLifecycle.GetProcess(bpmCfg)
563+
Expect(err).NotTo(HaveOccurred())
564+
Expect(process).To(Equal(&models.Process{
565+
Name: expectedContainerID,
566+
Pid: 0,
567+
Status: "failed",
568+
}))
569+
})
570+
})
571+
557572
Context("when the process name is the same as the job name", func() {
558573
BeforeEach(func() {
559574
bpmCfg = config.NewBPMConfig(expectedSystemRoot, expectedJobName, expectedJobName)
@@ -574,10 +589,10 @@ var _ = Describe("RuncJobLifecycle", func() {
574589
})
575590

576591
It("returns nil,nil", func() {
577-
job, err := runcLifecycle.GetProcess(bpmCfg)
592+
process, err := runcLifecycle.GetProcess(bpmCfg)
578593
Expect(err).NotTo(HaveOccurred())
579594

580-
Expect(job).To(BeNil())
595+
Expect(process).To(BeNil())
581596
})
582597
})
583598

0 commit comments

Comments
 (0)