Skip to content

Commit 7ad2a47

Browse files
committed
Merge pull request #4025 from technosophos/issue/3971
fix(deisctl): Switch from channels to io.Writers.
2 parents bd230bb + 28d4bb6 commit 7ad2a47

25 files changed

Lines changed: 318 additions & 402 deletions

deisctl/backend/backend.go

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
package backend
22

3-
import "sync"
3+
import (
4+
"io"
5+
"sync"
6+
)
47

58
// Backend interface is used to interact with the cluster control plane
69
type Backend interface {
7-
Create([]string, *sync.WaitGroup, chan string, chan error)
8-
Destroy([]string, *sync.WaitGroup, chan string, chan error)
9-
Start([]string, *sync.WaitGroup, chan string, chan error)
10-
Stop([]string, *sync.WaitGroup, chan string, chan error)
11-
Scale(string, int, *sync.WaitGroup, chan string, chan error)
10+
Create([]string, *sync.WaitGroup, io.Writer, io.Writer)
11+
Destroy([]string, *sync.WaitGroup, io.Writer, io.Writer)
12+
Start([]string, *sync.WaitGroup, io.Writer, io.Writer)
13+
Stop([]string, *sync.WaitGroup, io.Writer, io.Writer)
14+
Scale(string, int, *sync.WaitGroup, io.Writer, io.Writer)
1215
SSH(string) error
1316
ListUnits() error
1417
ListUnitFiles() error

deisctl/backend/fleet/create.go

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,28 @@ package fleet
22

33
import (
44
"fmt"
5+
"io"
56
"strings"
67
"sync"
78
"time"
89

910
"github.com/coreos/fleet/job"
1011
"github.com/coreos/fleet/schema"
1112
"github.com/coreos/fleet/unit"
13+
14+
"github.com/deis/deis/pkg/prettyprint"
1215
)
1316

1417
// Create schedules unit files for the given components.
1518
func (c *FleetClient) Create(
16-
targets []string, wg *sync.WaitGroup, outchan chan string, errchan chan error) {
19+
targets []string, wg *sync.WaitGroup, out, ew io.Writer) {
1720

1821
units := make([]*schema.Unit, len(targets))
1922

2023
for i, target := range targets {
2124
unitName, unitFile, err := c.createUnitFile(target)
2225
if err != nil {
23-
errchan <- err
26+
fmt.Fprintf(ew, "Error creating: %s\n", err)
2427
return
2528
}
2629
units[i] = &schema.Unit{
@@ -31,28 +34,29 @@ func (c *FleetClient) Create(
3134

3235
for _, unit := range units {
3336
wg.Add(1)
34-
go doCreate(c, unit, wg, outchan, errchan)
37+
go doCreate(c, unit, wg, out, ew)
3538
}
3639
}
3740

38-
func doCreate(c *FleetClient, unit *schema.Unit, wg *sync.WaitGroup, outchan chan string, errchan chan error) {
41+
func doCreate(c *FleetClient, unit *schema.Unit, wg *sync.WaitGroup, out, ew io.Writer) {
3942
defer wg.Done()
4043

4144
// create unit definition
4245
if err := c.Fleet.CreateUnit(unit); err != nil {
4346
// ignore units that already exist
4447
if err.Error() != "job already exists" {
45-
errchan <- err
48+
fmt.Fprintln(ew, err.Error())
4649
return
4750
}
4851
}
4952

5053
desiredState := string(job.JobStateLoaded)
51-
out := fmt.Sprintf("\033[0;33m%v:\033[0m loaded \r", unit.Name)
54+
tpl := prettyprint.Colorize("{{.Yellow}}%v:{{.Default}} loaded")
55+
msg := fmt.Sprintf(tpl, unit.Name)
5256

5357
// schedule the unit
5458
if err := c.Fleet.SetUnitTargetState(unit.Name, desiredState); err != nil {
55-
errchan <- err
59+
fmt.Fprintln(ew, err)
5660
return
5761
}
5862

@@ -62,7 +66,7 @@ outerLoop:
6266
time.Sleep(250 * time.Millisecond)
6367
unitStates, err := c.Fleet.UnitStates()
6468
if err != nil {
65-
errchan <- err
69+
fmt.Fprintln(ew, err)
6670
}
6771
for _, us := range unitStates {
6872
if strings.HasPrefix(us.Name, unit.Name) {
@@ -71,7 +75,7 @@ outerLoop:
7175
}
7276
}
7377

74-
outchan <- out
78+
fmt.Fprintln(out, msg)
7579
}
7680

7781
func (c *FleetClient) createUnitFile(target string) (unitName string, uf *unit.UnitFile, err error) {

deisctl/backend/fleet/create_test.go

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package fleet
22

33
import (
4-
"fmt"
54
"io/ioutil"
65
"path"
76
"sync"
@@ -34,19 +33,14 @@ func TestCreate(t *testing.T) {
3433
c := &FleetClient{templatePaths: []string{name}, Fleet: &testFleetClient}
3534

3635
var errOutput string
37-
outchan := make(chan string)
38-
errchan := make(chan error)
3936
var wg sync.WaitGroup
4037

4138
logMutex := sync.Mutex{}
4239

43-
go logState(outchan, errchan, &errOutput, &logMutex)
44-
45-
c.Create([]string{"controller", "builder", "router@1"}, &wg, outchan, errchan)
40+
se := newOutErr()
41+
c.Create([]string{"controller", "builder", "router@1"}, &wg, se.out, se.ew)
4642

4743
wg.Wait()
48-
close(errchan)
49-
close(outchan)
5044

5145
logMutex.Lock()
5246
if errOutput != "" {
@@ -68,7 +62,7 @@ func TestCreate(t *testing.T) {
6862
}
6963

7064
if !found {
71-
t.Error(fmt.Errorf("Expected Unit %s not found in Unit States", expectedUnit))
65+
t.Errorf("Expected Unit %s not found in Unit States", expectedUnit)
7266
}
7367
}
7468
}

deisctl/backend/fleet/destroy.go

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,42 +2,46 @@ package fleet
22

33
import (
44
"fmt"
5+
"io"
56
"strings"
67
"sync"
78
"time"
9+
10+
"github.com/deis/deis/pkg/prettyprint"
811
)
912

1013
// Destroy units for a given target
11-
func (c *FleetClient) Destroy(targets []string, wg *sync.WaitGroup, outchan chan string, errchan chan error) {
14+
func (c *FleetClient) Destroy(targets []string, wg *sync.WaitGroup, out, ew io.Writer) {
1215
// expand @* targets
1316
expandedTargets, err := c.expandTargets(targets)
1417
if err != nil {
15-
errchan <- err
18+
fmt.Fprintln(ew, err.Error())
1619
return
1720
}
1821

1922
for _, target := range expandedTargets {
2023
wg.Add(1)
21-
go doDestroy(c, target, wg, outchan, errchan)
24+
go doDestroy(c, target, wg, out, ew)
2225
}
2326
return
2427
}
2528

26-
func doDestroy(c *FleetClient, target string, wg *sync.WaitGroup, outchan chan string, errchan chan error) {
29+
func doDestroy(c *FleetClient, target string, wg *sync.WaitGroup, out, ew io.Writer) {
2730
defer wg.Done()
2831

2932
// prepare string representation
3033
component, num, err := splitTarget(target)
3134
if err != nil {
32-
errchan <- err
35+
fmt.Fprintln(ew, err.Error())
3336
return
3437
}
3538
name, err := formatUnitName(component, num)
3639
if err != nil {
37-
errchan <- err
40+
fmt.Fprintln(ew, err.Error())
3841
return
3942
}
40-
destroyed := fmt.Sprintf("\033[0;33m%v:\033[0m destroyed \r", name)
43+
tpl := prettyprint.Colorize("{{.Yellow}}%v:{{.Default}} destroyed")
44+
destroyed := fmt.Sprintf(tpl, name)
4145

4246
// tell fleet to destroy the unit
4347
c.Fleet.DestroyUnit(name)
@@ -48,14 +52,14 @@ outerLoop:
4852
time.Sleep(250 * time.Millisecond)
4953
unitStates, err := c.Fleet.UnitStates()
5054
if err != nil {
51-
errchan <- err
55+
fmt.Fprintln(ew, err.Error())
5256
}
5357
for _, us := range unitStates {
5458
if strings.HasPrefix(us.Name, name) {
5559
continue outerLoop
5660
}
5761
}
58-
outchan <- destroyed
62+
fmt.Fprintln(out, destroyed)
5963
return
6064
}
6165
}

deisctl/backend/fleet/destroy_test.go

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package fleet
22

33
import (
4-
"fmt"
54
"sync"
65
"testing"
76

@@ -28,19 +27,14 @@ func TestDestroy(t *testing.T) {
2827
c := &FleetClient{Fleet: &testFleetClient}
2928

3029
var errOutput string
31-
outchan := make(chan string)
32-
errchan := make(chan error)
3330
var wg sync.WaitGroup
3431

3532
logMutex := sync.Mutex{}
3633

37-
go logState(outchan, errchan, &errOutput, &logMutex)
38-
39-
c.Destroy([]string{"controller", "registry", "router@1"}, &wg, outchan, errchan)
34+
oe := newOutErr()
35+
c.Destroy([]string{"controller", "registry", "router@1"}, &wg, oe.out, oe.ew)
4036

4137
wg.Wait()
42-
close(errchan)
43-
close(outchan)
4438

4539
logMutex.Lock()
4640
if errOutput != "" {
@@ -49,6 +43,6 @@ func TestDestroy(t *testing.T) {
4943
logMutex.Unlock()
5044

5145
if len(testFleetClient.testUnits) != 1 || testFleetClient.testUnits[0].Name != "deis-builder.service" {
52-
t.Error(fmt.Errorf("Got %d Units (want 1), first unit %s (want builder)", len(testFleetClient.testUnits), testFleetClient.testUnits[0].Name))
46+
t.Errorf("Got %d Units (want 1), first unit %s (want builder)", len(testFleetClient.testUnits), testFleetClient.testUnits[0].Name)
5347
}
5448
}

deisctl/backend/fleet/fleet_test.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package fleet
22

33
import (
4+
"bytes"
45
"fmt"
56
"sync"
67
"testing"
@@ -103,6 +104,52 @@ func (c *stubFleetClient) DestroyUnit(name string) error {
103104
return nil
104105
}
105106

107+
func newOutErr() *outErr {
108+
return &outErr{
109+
&syncBuffer{},
110+
&syncBuffer{},
111+
}
112+
}
113+
114+
// Wrap output and error streams for ease of testing.
115+
type outErr struct {
116+
out, ew buffer
117+
}
118+
119+
// buffer represents a buffer for collecting written test output.
120+
//
121+
// This is used only in testing, so add more bytes.Buffer methods as needed.
122+
type buffer interface {
123+
Bytes() []byte
124+
String() string
125+
Write([]byte) (int, error)
126+
}
127+
128+
// syncBuffer simply synchronizes writes on a bytes.Buffer.
129+
type syncBuffer struct {
130+
bytes.Buffer
131+
mx sync.RWMutex
132+
}
133+
134+
func (s *syncBuffer) Write(b []byte) (int, error) {
135+
s.mx.Lock()
136+
defer s.mx.Unlock()
137+
return s.Buffer.Write(b)
138+
}
139+
140+
func (s *syncBuffer) String() string {
141+
s.mx.RLock()
142+
defer s.mx.RUnlock()
143+
return s.Buffer.String()
144+
}
145+
146+
func (s *syncBuffer) Bytes() []byte {
147+
s.mx.RLock()
148+
defer s.mx.RUnlock()
149+
return s.Buffer.Bytes()
150+
}
151+
152+
/*
106153
func logState(outchan chan string, errchan chan error, errOutput *string, mutex *sync.Mutex) {
107154
for {
108155
select {
@@ -125,6 +172,7 @@ func logState(outchan chan string, errchan chan error, errOutput *string, mutex
125172
}
126173
}
127174
}
175+
*/
128176

129177
func TestNewClient(t *testing.T) {
130178
t.Parallel()

deisctl/backend/fleet/list_unit_files_test.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package fleet
22

33
import (
44
"bytes"
5-
"fmt"
65
"sync"
76
"testing"
87
"text/tabwriter"
@@ -80,6 +79,6 @@ deis-router@1.service 1182ecf launched launched 654321.../2.2.2.2
8079
actual := testWriter.String()
8180

8281
if expected != actual {
83-
t.Error(fmt.Errorf("Expected '%s', Got '%s'", expected, actual))
82+
t.Errorf("Expected '%s', Got '%s'", expected, actual)
8483
}
8584
}

deisctl/backend/fleet/list_units_test.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package fleet
22

33
import (
44
"bytes"
5-
"fmt"
65
"sync"
76
"testing"
87
"text/tabwriter"
@@ -70,6 +69,6 @@ deis-router@1.service 654321.../2.2.2.2 loaded active running
7069
actual := testWriter.String()
7170

7271
if expected != actual {
73-
t.Error(fmt.Errorf("Expected '%s', Got '%s'", expected, actual))
72+
t.Errorf("Expected '%s', Got '%s'", expected, actual)
7473
}
7574
}

0 commit comments

Comments
 (0)