forked from cloudfoundry/bosh-cli
/
vms.go
139 lines (109 loc) · 2.92 KB
/
vms.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package cmd
import (
"fmt"
"code.cloudfoundry.org/workpool"
boshdir "github.com/cloudfoundry/bosh-cli/director"
boshui "github.com/cloudfoundry/bosh-cli/ui"
boshtbl "github.com/cloudfoundry/bosh-cli/ui/table"
bosherr "github.com/cloudfoundry/bosh-utils/errors"
)
type VMsCmd struct {
ui boshui.UI
director boshdir.Director
parallel int
}
type deploymentInfo struct {
depName string
vmInfos []boshdir.VMInfo
}
func NewVMsCmd(ui boshui.UI, director boshdir.Director, parallel int) VMsCmd {
return VMsCmd{ui: ui, director: director, parallel: parallel}
}
func (c VMsCmd) Run(opts VMsOpts) error {
instTable := InstanceTable{
// VMs command should always show VM specifics
VMDetails: true,
Details: false,
DNS: opts.DNS,
Vitals: opts.Vitals,
CloudProperties: opts.CloudProperties,
}
if len(opts.Deployment) > 0 {
dep, err := c.director.FindDeployment(opts.Deployment)
if err != nil {
return err
}
vmInfos, err := dep.VMInfos()
if err != nil {
return err
}
c.printDeployment(dep, instTable, vmInfos)
return nil
}
return c.printDeployments(instTable, c.parallel)
}
func (c VMsCmd) printDeployments(instTable InstanceTable, parallel int) error {
deployments, err := c.director.Deployments()
if err != nil {
return err
}
vmInfos, err := parallelVMInfos(deployments, parallel)
for _, dep := range deployments {
if vmInfo, ok := vmInfos[dep.Name()]; ok {
c.printDeployment(dep, instTable, vmInfo)
}
}
return err
}
func parallelVMInfos(deployments []boshdir.Deployment, parallel int) (map[string][]boshdir.VMInfo, error) {
if parallel == 0 {
parallel = 1
}
workSize := len(deployments)
resultc := make(chan deploymentInfo, workSize)
errorc := make(chan error, workSize)
defer close(resultc)
defer close(errorc)
works := make([]func(), workSize)
for i, dep := range deployments {
dep := dep
works[i] = func() {
vmInfos, err := dep.VMInfos()
errorc <- err
resultc <- deploymentInfo{dep.Name(), vmInfos}
}
}
throttler, err := workpool.NewThrottler(parallel, works)
if err != nil {
return nil, err
}
throttler.Work()
vms := make(map[string][]boshdir.VMInfo, workSize)
var vmInfoErrors []error
for i := 0; i < workSize; i++ {
errc := <-errorc
result := <-resultc
if errc != nil {
vmInfoErrors = append(vmInfoErrors, errc)
} else {
vms[result.depName] = result.vmInfos
}
}
if len(vmInfoErrors) > 0 {
err = bosherr.NewMultiError(vmInfoErrors...)
}
return vms, err
}
func (c VMsCmd) printDeployment(dep boshdir.Deployment, instTable InstanceTable, vmInfos []boshdir.VMInfo) {
table := boshtbl.Table{
Title: fmt.Sprintf("Deployment '%s'", dep.Name()),
Content: "vms",
Header: instTable.Headers(),
SortBy: []boshtbl.ColumnSort{{Column: 0, Asc: true}},
}
for _, info := range vmInfos {
row := instTable.AsValues(instTable.ForVMInfo(info))
table.Rows = append(table.Rows, row)
}
c.ui.PrintTable(table)
}