Skip to content

Commit 4446ba6

Browse files
feat: worker view and work-pool view support -f parameter (#537)
* feat: implement -f output format support json,table,basic for deployment-target view * feat: implement output-format (-f) parameter for worker-pool view * switch back to default table view * handle open web flag * refactor * Fix endcode issue for healthStatus in json format
1 parent 2cd8853 commit 4446ba6

File tree

9 files changed

+356
-27
lines changed

9 files changed

+356
-27
lines changed

pkg/cmd/worker/listening-tentacle/view/view.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ func NewCmdView(f factory.Factory) *cobra.Command {
2525
$ %[1]s worker listening-tentacle view Machines-100
2626
`, constants.ExecutableName),
2727
RunE: func(c *cobra.Command, args []string) error {
28-
opts := shared.NewViewOptions(flags, cmd.NewDependencies(f, c), args)
28+
opts := shared.NewViewOptions(flags, cmd.NewDependencies(f, c), args, c)
2929
return ViewRun(opts)
3030
},
3131
}

pkg/cmd/worker/polling-tentacle/view/view.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ func NewCmdView(f factory.Factory) *cobra.Command {
2525
$ %[1]s worker polling-tentacle view Machines-100
2626
`, constants.ExecutableName),
2727
RunE: func(c *cobra.Command, args []string) error {
28-
opts := shared.NewViewOptions(flags, cmd.NewDependencies(f, c), args)
28+
opts := shared.NewViewOptions(flags, cmd.NewDependencies(f, c), args, c)
2929
return ViewRun(opts)
3030
},
3131
}

pkg/cmd/worker/shared/view.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"github.com/OctopusDeploy/cli/pkg/machinescommon"
77
"github.com/OctopusDeploy/cli/pkg/output"
88
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/machines"
9+
"github.com/spf13/cobra"
910
)
1011

1112
type ContributeEndpointCallback func(opts *ViewOptions, endpoint machines.IEndpoint) ([]*output.DataRow, error)
@@ -18,6 +19,7 @@ type ViewOptions struct {
1819
*cmd.Dependencies
1920
IdOrName string
2021
*ViewFlags
22+
Command *cobra.Command
2123
}
2224

2325
func NewViewFlags() *ViewFlags {
@@ -26,11 +28,12 @@ func NewViewFlags() *ViewFlags {
2628
}
2729
}
2830

29-
func NewViewOptions(viewFlags *ViewFlags, dependencies *cmd.Dependencies, args []string) *ViewOptions {
31+
func NewViewOptions(viewFlags *ViewFlags, dependencies *cmd.Dependencies, args []string, command *cobra.Command) *ViewOptions {
3032
return &ViewOptions{
3133
ViewFlags: viewFlags,
3234
Dependencies: dependencies,
3335
IdOrName: args[0],
36+
Command: command,
3437
}
3538
}
3639

pkg/cmd/worker/ssh/view/view.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ func NewCmdView(f factory.Factory) *cobra.Command {
2525
$ %[1]s worker ssh view Machines-100
2626
`, constants.ExecutableName),
2727
RunE: func(c *cobra.Command, args []string) error {
28-
opts := shared.NewViewOptions(flags, cmd.NewDependencies(f, c), args)
28+
opts := shared.NewViewOptions(flags, cmd.NewDependencies(f, c), args, c)
2929
return ViewRun(opts)
3030
},
3131
}

pkg/cmd/worker/view/view.go

Lines changed: 165 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,18 @@ package view
22

33
import (
44
"fmt"
5+
"strings"
56

67
"github.com/MakeNowJust/heredoc/v2"
78
"github.com/OctopusDeploy/cli/pkg/cmd"
8-
listeningTentacle "github.com/OctopusDeploy/cli/pkg/cmd/worker/listening-tentacle/view"
9-
pollingTentacle "github.com/OctopusDeploy/cli/pkg/cmd/worker/polling-tentacle/view"
109
"github.com/OctopusDeploy/cli/pkg/cmd/worker/shared"
11-
ssh "github.com/OctopusDeploy/cli/pkg/cmd/worker/ssh/view"
1210
"github.com/OctopusDeploy/cli/pkg/constants"
1311
"github.com/OctopusDeploy/cli/pkg/factory"
1412
"github.com/OctopusDeploy/cli/pkg/machinescommon"
13+
"github.com/OctopusDeploy/cli/pkg/output"
1514
"github.com/OctopusDeploy/cli/pkg/usage"
15+
"github.com/OctopusDeploy/cli/pkg/util"
16+
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/machines"
1617
"github.com/spf13/cobra"
1718
)
1819

@@ -28,7 +29,7 @@ func NewCmdView(f factory.Factory) *cobra.Command {
2829
$ %[1]s worker view 'worker'
2930
`, constants.ExecutableName),
3031
RunE: func(c *cobra.Command, args []string) error {
31-
return ViewRun(shared.NewViewOptions(flags, cmd.NewDependencies(f, c), args))
32+
return ViewRun(shared.NewViewOptions(flags, cmd.NewDependencies(f, c), args, c))
3233
},
3334
}
3435

@@ -43,14 +44,169 @@ func ViewRun(opts *shared.ViewOptions) error {
4344
return err
4445
}
4546

46-
switch worker.Endpoint.GetCommunicationStyle() {
47+
err = output.PrintResource(worker, opts.Command, output.Mappers[*machines.Worker]{
48+
Json: func(w *machines.Worker) any {
49+
return getWorkerAsJson(opts, w)
50+
},
51+
Table: output.TableDefinition[*machines.Worker]{
52+
Header: []string{"NAME", "TYPE", "HEALTH", "STATUS", "WORKER POOLS", "ENDPOINT DETAILS"},
53+
Row: func(w *machines.Worker) []string {
54+
return getWorkerAsTableRow(opts, w)
55+
},
56+
},
57+
Basic: func(w *machines.Worker) string {
58+
return getWorkerAsBasic(opts, w)
59+
},
60+
})
61+
if err != nil {
62+
return err
63+
}
64+
65+
if opts.WebFlags != nil && opts.WebFlags.Web.Value {
66+
machinescommon.DoWebForWorkers(worker, opts.Dependencies, opts.WebFlags, getWorkerTypeDisplayName(worker.Endpoint.GetCommunicationStyle()))
67+
}
68+
69+
return nil
70+
}
71+
72+
type WorkerAsJson struct {
73+
Id string `json:"Id"`
74+
Name string `json:"Name"`
75+
HealthStatus string `json:"HealthStatus"`
76+
StatusSummary string `json:"StatusSummary"`
77+
CommunicationStyle string `json:"CommunicationStyle"`
78+
WorkerPools []string `json:"WorkerPools"`
79+
EndpointDetails map[string]string `json:"EndpointDetails"`
80+
WebUrl string `json:"WebUrl"`
81+
}
82+
83+
func getWorkerAsJson(opts *shared.ViewOptions, worker *machines.Worker) WorkerAsJson {
84+
workerPoolMap, _ := shared.GetWorkerPoolMap(opts)
85+
workerPoolNames := resolveValues(worker.WorkerPoolIDs, workerPoolMap)
86+
87+
endpointDetails := getEndpointDetails(worker)
88+
89+
return WorkerAsJson{
90+
Id: worker.GetID(),
91+
Name: worker.Name,
92+
HealthStatus: worker.HealthStatus,
93+
StatusSummary: worker.StatusSummary,
94+
CommunicationStyle: worker.Endpoint.GetCommunicationStyle(),
95+
WorkerPools: workerPoolNames,
96+
EndpointDetails: endpointDetails,
97+
WebUrl: util.GenerateWebURL(opts.Host, worker.SpaceID, fmt.Sprintf("infrastructure/workers/%s/settings", worker.GetID())),
98+
}
99+
}
100+
101+
func getWorkerAsTableRow(opts *shared.ViewOptions, worker *machines.Worker) []string {
102+
workerPoolMap, _ := shared.GetWorkerPoolMap(opts)
103+
workerPoolNames := resolveValues(worker.WorkerPoolIDs, workerPoolMap)
104+
105+
endpointDetails := getEndpointDetails(worker)
106+
endpointDetailsStr := formatEndpointDetailsForTable(endpointDetails)
107+
108+
return []string{
109+
worker.Name,
110+
getWorkerTypeDisplayName(worker.Endpoint.GetCommunicationStyle()),
111+
getHealthStatusFormatted(worker.HealthStatus),
112+
worker.StatusSummary,
113+
strings.Join(workerPoolNames, ", "),
114+
endpointDetailsStr,
115+
}
116+
}
117+
118+
func getWorkerAsBasic(opts *shared.ViewOptions, worker *machines.Worker) string {
119+
var result strings.Builder
120+
121+
result.WriteString(fmt.Sprintf("%s %s\n", output.Bold(worker.Name), output.Dimf("(%s)", worker.GetID())))
122+
result.WriteString(fmt.Sprintf("Health status: %s\n", getHealthStatusFormatted(worker.HealthStatus)))
123+
result.WriteString(fmt.Sprintf("Current status: %s\n", worker.StatusSummary))
124+
result.WriteString(fmt.Sprintf("Communication style: %s\n", getWorkerTypeDisplayName(worker.Endpoint.GetCommunicationStyle())))
125+
126+
workerPoolMap, _ := shared.GetWorkerPoolMap(opts)
127+
workerPoolNames := resolveValues(worker.WorkerPoolIDs, workerPoolMap)
128+
result.WriteString(fmt.Sprintf("Worker Pools: %s\n", output.FormatAsList(workerPoolNames)))
129+
130+
// Add endpoint-specific details
131+
endpointDetails := getEndpointDetails(worker)
132+
for key, value := range endpointDetails {
133+
result.WriteString(fmt.Sprintf("%s: %s\n", key, value))
134+
}
135+
136+
// Web URL
137+
url := util.GenerateWebURL(opts.Host, worker.SpaceID, fmt.Sprintf("infrastructure/workers/%s/settings", worker.GetID()))
138+
result.WriteString(fmt.Sprintf("\nView this worker in Octopus Deploy: %s\n", output.Blue(url)))
139+
140+
return result.String()
141+
}
142+
143+
func getHealthStatusFormatted(status string) string {
144+
switch status {
145+
case "Healthy":
146+
return output.Green(status)
147+
case "Unhealthy":
148+
return output.Red(status)
149+
case "HasWarnings":
150+
return output.Yellow("Has Warnings")
151+
case "Unavailable":
152+
return output.Dim(status)
153+
default:
154+
return status
155+
}
156+
}
157+
158+
func getWorkerTypeDisplayName(communicationStyle string) string {
159+
switch communicationStyle {
47160
case "TentaclePassive":
48-
return listeningTentacle.ViewRun(opts)
161+
return "Listening Tentacle"
49162
case "TentacleActive":
50-
return pollingTentacle.ViewRun(opts)
163+
return "Polling Tentacle"
51164
case "Ssh":
52-
return ssh.ViewRun(opts)
165+
return "SSH"
166+
default:
167+
return communicationStyle
168+
}
169+
}
170+
171+
func getEndpointDetails(worker *machines.Worker) map[string]string {
172+
details := make(map[string]string)
173+
174+
switch endpoint := worker.Endpoint.(type) {
175+
case *machines.ListeningTentacleEndpoint:
176+
details["URI"] = endpoint.URI.String()
177+
if endpoint.TentacleVersionDetails != nil {
178+
details["Tentacle version"] = endpoint.TentacleVersionDetails.Version
179+
}
180+
case *machines.PollingTentacleEndpoint:
181+
if endpoint.TentacleVersionDetails != nil {
182+
details["Tentacle version"] = endpoint.TentacleVersionDetails.Version
183+
}
184+
case *machines.SSHEndpoint:
185+
details["URI"] = endpoint.URI.String()
186+
if endpoint.DotNetCorePlatform != "" {
187+
details["Platform"] = endpoint.DotNetCorePlatform
188+
}
53189
}
54190

55-
return fmt.Errorf("unsupported worker '%s'", worker.Endpoint.GetCommunicationStyle())
191+
return details
192+
}
193+
194+
func formatEndpointDetailsForTable(details map[string]string) string {
195+
var parts []string
196+
for key, value := range details {
197+
parts = append(parts, fmt.Sprintf("%s: %s", key, value))
198+
}
199+
return strings.Join(parts, "; ")
200+
}
201+
202+
func resolveValues(keys []string, lookup map[string]string) []string {
203+
var result []string
204+
for _, key := range keys {
205+
if value, exists := lookup[key]; exists {
206+
result = append(result, value)
207+
} else {
208+
result = append(result, key)
209+
}
210+
}
211+
return result
56212
}

pkg/cmd/workerpool/dynamic/view/view.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ func NewCmdView(f factory.Factory) *cobra.Command {
2525
$ %[1]s worker-pool dynamic view 'Hosted Workers'
2626
`, constants.ExecutableName),
2727
RunE: func(c *cobra.Command, args []string) error {
28-
return ViewRun(shared.NewViewOptions(flags, cmd.NewDependencies(f, c), args))
28+
return ViewRun(shared.NewViewOptions(flags, cmd.NewDependencies(f, c), args, c))
2929
},
3030
}
3131

pkg/cmd/workerpool/shared/view.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"github.com/OctopusDeploy/cli/pkg/machinescommon"
77
"github.com/OctopusDeploy/cli/pkg/output"
88
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/workerpools"
9+
"github.com/spf13/cobra"
910
)
1011

1112
type ContributeDetailsCallback func(opts *ViewOptions, workerPool workerpools.IWorkerPool) ([]*output.DataRow, error)
@@ -18,6 +19,7 @@ type ViewOptions struct {
1819
*cmd.Dependencies
1920
IdOrName string
2021
*ViewFlags
22+
Command *cobra.Command
2123
}
2224

2325
func NewViewFlags() *ViewFlags {
@@ -26,11 +28,12 @@ func NewViewFlags() *ViewFlags {
2628
}
2729
}
2830

29-
func NewViewOptions(viewFlags *ViewFlags, dependencies *cmd.Dependencies, args []string) *ViewOptions {
31+
func NewViewOptions(viewFlags *ViewFlags, dependencies *cmd.Dependencies, args []string, command *cobra.Command) *ViewOptions {
3032
return &ViewOptions{
3133
ViewFlags: viewFlags,
3234
Dependencies: dependencies,
3335
IdOrName: args[0],
36+
Command: command,
3437
}
3538
}
3639

pkg/cmd/workerpool/static/view/view.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ func NewCmdView(f factory.Factory) *cobra.Command {
2828
$ %[1]s worker-pool static view 'windows workers'
2929
`, constants.ExecutableName),
3030
RunE: func(c *cobra.Command, args []string) error {
31-
return ViewRun(shared.NewViewOptions(flags, cmd.NewDependencies(f, c), args))
31+
return ViewRun(shared.NewViewOptions(flags, cmd.NewDependencies(f, c), args, c))
3232
},
3333
}
3434

0 commit comments

Comments
 (0)