Skip to content

Commit 082ddef

Browse files
authored
fix(server): re-add --show-ip-addresses support for machine output (#288)
Implements #283
1 parent 7a76c3c commit 082ddef

3 files changed

Lines changed: 119 additions & 19 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
88
## [Unreleased]
99

1010
### Added
11+
1112
- Add `gateway` commands (`delete`, `list`) for Network gateway management.
13+
- In machine readable outputs of server list, add support for `--show-ip-addresses` parameter.
1214

1315
## [3.3.0] - 2024-01-23
1416

internal/commands/server/list.go

Lines changed: 36 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,22 @@ func ListCommand() commands.Command {
2929
}
3030
}
3131

32-
type listIPAddress struct {
33-
Access string `json:"access"`
34-
Address string `json:"address"`
35-
Floating bool `json:"floating"`
36-
}
37-
3832
type listServerIpaddresses struct {
3933
ServerUUID string
40-
IPAddresses []listIPAddress
34+
IPAddresses upcloud.IPAddressSlice
4135
Error error
4236
}
4337

38+
type serverWithIPAddress struct {
39+
upcloud.Server
40+
41+
IPAddresses upcloud.IPAddressSlice `json:"ip_addresses"`
42+
}
43+
44+
type serversWithIPAddresses struct {
45+
Servers []serverWithIPAddress `json:"servers"`
46+
}
47+
4448
type listCommand struct {
4549
*commands.BaseCommand
4650
showIPAddresses string
@@ -88,6 +92,7 @@ func (ls *listCommand) ExecuteWithoutArguments(exec commands.Executor) (output.O
8892
}
8993

9094
if ls.showIPAddresses != "none" {
95+
serversWithIPs := serversWithIPAddresses{}
9196
ipaddressMap, err := getIPAddressesByServerUUID(servers, ls.showIPAddresses, exec)
9297
if err != nil {
9398
return nil, err
@@ -96,20 +101,35 @@ func (ls *listCommand) ExecuteWithoutArguments(exec commands.Executor) (output.O
96101
for i, row := range rows {
97102
uuid := row[0].(string)
98103

99-
var listIpaddresses []listIPAddress
104+
// Add IPs to the table in human output
105+
var listIpaddresses upcloud.IPAddressSlice
100106
if serverIpaddresses, ok := ipaddressMap[uuid]; ok {
101107
listIpaddresses = append(listIpaddresses, serverIpaddresses.IPAddresses...)
102108
}
103109
row = append(row[:3], row[2:]...)
104110
row[2] = listIpaddresses
105111
rows[i] = row
112+
113+
// Add IPs to machine output
114+
serversWithIPs.Servers = append(serversWithIPs.Servers, serverWithIPAddress{
115+
Server: servers.Servers[i],
116+
IPAddresses: listIpaddresses,
117+
})
106118
}
107119
columns = append(columns[:3], columns[2:]...)
108120
columns[2] = output.TableColumn{
109121
Key: "ip_addresses",
110122
Header: "IP addresses",
111123
Format: formatListIPAddresses,
112124
}
125+
126+
return output.MarshaledWithHumanOutput{
127+
Value: serversWithIPs,
128+
Output: output.Table{
129+
Columns: columns,
130+
Rows: rows,
131+
},
132+
}, nil
113133
}
114134

115135
return output.MarshaledWithHumanOutput{
@@ -152,21 +172,18 @@ func getIPAddressesByServerUUID(servers *upcloud.Servers, accessType string, exe
152172
return ipaddressMap, nil
153173
}
154174

155-
func getServerIPAddresses(uuid, accessType string, exec commands.Executor) ([]listIPAddress, error) {
175+
func getServerIPAddresses(uuid, accessType string, exec commands.Executor) (upcloud.IPAddressSlice, error) {
156176
server, err := exec.All().GetServerNetworks(exec.Context(), &request.GetServerNetworksRequest{ServerUUID: uuid})
157177
if err != nil {
158178
return nil, err
159179
}
160180

161-
var ipaddresses []listIPAddress
181+
var ipaddresses upcloud.IPAddressSlice
162182
for _, iface := range server.Interfaces {
163183
for _, ipa := range iface.IPAddresses {
164184
if accessType == "all" || iface.Type == accessType {
165-
ipaddresses = append(ipaddresses, listIPAddress{
166-
Access: iface.Type,
167-
Address: ipa.Address,
168-
Floating: ipa.Floating.Bool(),
169-
})
185+
ipa.Access = iface.Type
186+
ipaddresses = append(ipaddresses, ipa)
170187
}
171188
}
172189
}
@@ -186,22 +203,22 @@ func getServerIPAddresses(uuid, accessType string, exec commands.Executor) ([]li
186203
return accessMap[ipaddresses[i].Access] > accessMap[ipaddresses[j].Access]
187204
}
188205

189-
return floatingMap[ipaddresses[i].Floating] > floatingMap[ipaddresses[j].Floating]
206+
return floatingMap[ipaddresses[i].Floating.Bool()] > floatingMap[ipaddresses[j].Floating.Bool()]
190207
})
191208

192209
return ipaddresses, nil
193210
}
194211

195212
func formatListIPAddresses(val interface{}) (text.Colors, string, error) {
196-
ipaddresses, ok := val.([]listIPAddress)
213+
ipaddresses, ok := val.(upcloud.IPAddressSlice)
197214
if !ok {
198-
return nil, "", fmt.Errorf("cannot parse IP addresses from %T, expected []listIPAddress", val)
215+
return nil, "", fmt.Errorf("cannot parse IP addresses from %T, expected upcloud.IPAddressSlice", val)
199216
}
200217

201218
var rows []string
202219
for _, ipa := range ipaddresses {
203220
var floating string
204-
if ipa.Floating {
221+
if ipa.Floating.Bool() {
205222
floating = " (f)"
206223
}
207224

internal/commands/server/list_test.go

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,72 @@ import (
1414
"github.com/stretchr/testify/assert"
1515
)
1616

17+
const expectedJSONOutput = `
18+
{
19+
"servers": [
20+
{
21+
"core_number": "0",
22+
"hostname": "server-list-test-server",
23+
"license": 0,
24+
"memory_amount": "0",
25+
"plan": "1xCPU-1GB",
26+
"progress": "0",
27+
"state": "started",
28+
"tags": null,
29+
"title": "",
30+
"uuid": "server-list-test-server-uuid",
31+
"zone": "pl-waw1",
32+
"ip_addresses": [
33+
{
34+
"access": "public",
35+
"address": "10.0.97.4",
36+
"family": "",
37+
"part_of_plan": "no",
38+
"ptr_record": "",
39+
"server": "",
40+
"mac": "",
41+
"floating": "yes",
42+
"zone": ""
43+
},
44+
{
45+
"access": "public",
46+
"address": "10.0.98.3",
47+
"family": "",
48+
"part_of_plan": "no",
49+
"ptr_record": "",
50+
"server": "",
51+
"mac": "",
52+
"floating": "no",
53+
"zone": ""
54+
},
55+
{
56+
"access": "private",
57+
"address": "10.0.99.2",
58+
"family": "",
59+
"part_of_plan": "no",
60+
"ptr_record": "",
61+
"server": "",
62+
"mac": "",
63+
"floating": "no",
64+
"zone": ""
65+
},
66+
{
67+
"access": "utility",
68+
"address": "10.0.100.1",
69+
"family": "",
70+
"part_of_plan": "no",
71+
"ptr_record": "",
72+
"server": "",
73+
"mac": "",
74+
"floating": "no",
75+
"zone": ""
76+
}
77+
]
78+
}
79+
]
80+
}
81+
`
82+
1783
func TestListServers(t *testing.T) {
1884
text.DisableColors()
1985

@@ -74,8 +140,10 @@ func TestListServers(t *testing.T) {
74140
for _, test := range []struct {
75141
name string
76142
args []string
143+
json bool
77144
outputContains []string
78145
outputNotContains []string
146+
outputJSONEquals string
79147
}{
80148
{
81149
name: "No args",
@@ -122,9 +190,18 @@ func TestListServers(t *testing.T) {
122190
"utility: 10.0.100.1",
123191
},
124192
},
193+
{
194+
name: "JSON output",
195+
args: []string{"--show-ip-addresses"},
196+
json: true,
197+
outputJSONEquals: expectedJSONOutput,
198+
},
125199
} {
126200
t.Run(test.name, func(t *testing.T) {
127201
conf := config.New()
202+
if test.json {
203+
conf.Viper().Set(config.KeyOutput, config.ValueOutputJSON)
204+
}
128205

129206
testCmd := ListCommand()
130207
mService := new(smock.Service)
@@ -145,6 +222,10 @@ func TestListServers(t *testing.T) {
145222
for _, notContains := range test.outputNotContains {
146223
assert.NotContains(t, output, notContains)
147224
}
225+
226+
if len(test.outputJSONEquals) > 0 {
227+
assert.JSONEq(t, test.outputJSONEquals, output)
228+
}
148229
})
149230
}
150231
}

0 commit comments

Comments
 (0)