Skip to content

Commit f865d4c

Browse files
authored
feat(instance): get server-type list info from PCU (#5379)
1 parent e0b1670 commit f865d4c

File tree

4 files changed

+904
-641
lines changed

4 files changed

+904
-641
lines changed

internal/namespaces/instance/v1/custom.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ func GetCommands() *core.Commands {
8181
instance.ServerTypesAvailability(""),
8282
human.EnumMarshalFunc(serverTypesAvailabilityMarshalSpecs),
8383
)
84+
human.RegisterMarshalerFunc([]*customServerType{}, serverTypesListMarshalerFunc)
8485

8586
cmds.MustFind("instance", "server-type", "list").Override(serverTypeListBuilder)
8687

internal/namespaces/instance/v1/custom_server_type.go

Lines changed: 132 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ import (
44
"context"
55
"errors"
66
"fmt"
7-
"sort"
87
"strings"
98

109
"github.com/fatih/color"
1110
"github.com/scaleway/scaleway-cli/v2/core"
1211
"github.com/scaleway/scaleway-cli/v2/core/human"
1312
"github.com/scaleway/scaleway-sdk-go/api/instance/v1"
13+
product_catalog "github.com/scaleway/scaleway-sdk-go/api/product_catalog/v2alpha1"
1414
"github.com/scaleway/scaleway-sdk-go/scw"
1515
)
1616

@@ -30,6 +30,43 @@ var serverTypesAvailabilityMarshalSpecs = human.EnumMarshalSpecs{
3030
},
3131
}
3232

33+
// serverTypesListMarshalerFunc marshals a Server Type for the list view.
34+
// This is mostly done to discard local_volume_max_size from the human output but keep it in other outputs.
35+
func serverTypesListMarshalerFunc(i any, opt *human.MarshalOpt) (string, error) {
36+
// humanServerTypeInList is the custom ServerType type used for list view.
37+
type humanServerTypeInList struct {
38+
Name string
39+
HourlyPrice *scw.Money
40+
SupportedStorage string
41+
CPU uint32
42+
GPU uint32
43+
RAM scw.Size
44+
Arch string
45+
Bandwidth scw.Size
46+
Availability instance.ServerTypesAvailability
47+
MaxFileSystems uint32
48+
}
49+
50+
customServerTypes := i.([]*customServerType)
51+
humanServerTypes := make([]*humanServerTypeInList, 0, len(customServerTypes))
52+
for _, serverType := range customServerTypes {
53+
humanServerTypes = append(humanServerTypes, &humanServerTypeInList{
54+
Name: serverType.Name,
55+
HourlyPrice: serverType.HourlyPrice,
56+
SupportedStorage: serverType.SupportedStorage,
57+
CPU: serverType.CPU,
58+
GPU: serverType.GPU,
59+
RAM: serverType.RAM,
60+
Arch: serverType.Arch,
61+
Bandwidth: serverType.Bandwidth,
62+
Availability: serverType.Availability,
63+
MaxFileSystems: serverType.MaxFileSystems,
64+
})
65+
}
66+
67+
return human.Marshal(humanServerTypes, opt)
68+
}
69+
3370
//
3471
// Builders
3572
//
@@ -38,57 +75,51 @@ type customServerType struct {
3875
Name string `json:"name"`
3976
HourlyPrice *scw.Money `json:"hourly_price"`
4077
LocalVolumeMaxSize scw.Size `json:"local_volume_max_size"`
78+
SupportedStorage string `json:"supported_storage"`
4179
CPU uint32 `json:"cpu"`
42-
GPU *uint64 `json:"gpu"`
80+
GPU uint32 `json:"gpu"`
4381
RAM scw.Size `json:"ram"`
44-
Arch instance.Arch `json:"arch"`
82+
Arch string `json:"arch"`
83+
Bandwidth scw.Size `json:"bandwidth"`
4584
Availability instance.ServerTypesAvailability `json:"availability"`
4685
MaxFileSystems uint32 `json:"max_file_systems"`
4786
}
4887

4988
// serverTypeListBuilder transforms the server map into a list to display a
5089
// table of server types instead of a flat key/value list.
51-
// We need it for:
52-
// - [APIGW-1932] hide deprecated instance for scw instance server-type list
90+
// Most properties are now fetched from the PCU, including lifecycle status, and server types are displayed according
91+
// to said status.
5392
func serverTypeListBuilder(c *core.Command) *core.Command {
54-
deprecatedNames := map[string]struct{}{
55-
"START1-L": {},
56-
"START1-M": {},
57-
"START1-S": {},
58-
"START1-XS": {},
59-
"VC1L": {},
60-
"VC1M": {},
61-
"VC1S": {},
62-
"X64-120GB": {},
63-
"X64-15GB": {},
64-
"X64-30GB": {},
65-
"X64-60GB": {},
66-
"C1": {},
67-
"C2M": {},
68-
"C2L": {},
69-
"C2S": {},
70-
"ARM64-2GB": {},
71-
"ARM64-4GB": {},
72-
"ARM64-8GB": {},
73-
"ARM64-16GB": {},
74-
"ARM64-32GB": {},
75-
"ARM64-64GB": {},
76-
"ARM64-128GB": {},
77-
}
78-
7993
c.Run = func(ctx context.Context, argsI any) (any, error) {
80-
api := instance.NewAPI(core.ExtractClient(ctx))
94+
pcuAPI := product_catalog.NewPublicCatalogAPI(core.ExtractClient(ctx))
95+
instanceAPI := instance.NewAPI(core.ExtractClient(ctx))
8196

82-
// Get server types.
97+
// Get server types from Product Catalog API
8398
request := argsI.(*instance.ListServersTypesRequest)
84-
listServersTypesResponse, err := api.ListServersTypes(request, scw.WithAllPages())
99+
instanceProductType := product_catalog.ListPublicCatalogProductsRequestProductTypeInstance
100+
listServersTypesResponse, err := pcuAPI.ListPublicCatalogProducts(
101+
&product_catalog.PublicCatalogAPIListPublicCatalogProductsRequest{
102+
ProductTypes: []product_catalog.ListPublicCatalogProductsRequestProductType{
103+
instanceProductType,
104+
},
105+
Zone: &request.Zone,
106+
Status: nil,
107+
},
108+
scw.WithAllPages(),
109+
scw.WithContext(ctx),
110+
)
111+
if err != nil {
112+
return nil, err
113+
}
114+
115+
// Get server types from Instance API (still needed for the number of file systems)
116+
computeServerTypes, err := instanceAPI.ListServersTypes(request, scw.WithAllPages())
85117
if err != nil {
86118
return nil, err
87119
}
88-
serverTypes := []*customServerType(nil)
89120

90121
// Get server availabilities.
91-
availabilitiesResponse, err := api.GetServerTypesAvailability(
122+
availabilitiesResponse, err := instanceAPI.GetServerTypesAvailability(
92123
&instance.GetServerTypesAvailabilityRequest{
93124
Zone: request.Zone,
94125
},
@@ -98,55 +129,81 @@ func serverTypeListBuilder(c *core.Command) *core.Command {
98129
return nil, err
99130
}
100131

101-
for name, serverType := range listServersTypesResponse.Servers {
102-
_, isDeprecated := deprecatedNames[name]
103-
if isDeprecated {
132+
serverTypes := []*customServerType(nil)
133+
134+
for _, pcuServerType := range listServersTypesResponse.Products {
135+
switch pcuServerType.Status {
136+
case product_catalog.PublicCatalogProductStatusUnknownStatus:
137+
continue
138+
case product_catalog.PublicCatalogProductStatusPublicBeta:
139+
case product_catalog.PublicCatalogProductStatusPreview:
140+
case product_catalog.PublicCatalogProductStatusGeneralAvailability:
141+
case product_catalog.PublicCatalogProductStatusEndOfNewFeatures:
142+
case product_catalog.PublicCatalogProductStatusEndOfGrowth:
143+
continue
144+
case product_catalog.PublicCatalogProductStatusEndOfDeployment:
145+
continue
146+
case product_catalog.PublicCatalogProductStatusEndOfSupport:
147+
continue
148+
case product_catalog.PublicCatalogProductStatusEndOfSale:
149+
continue
150+
case product_catalog.PublicCatalogProductStatusEndOfLife:
151+
continue
152+
case product_catalog.PublicCatalogProductStatusRetired:
104153
continue
105154
}
106155

107-
serverTypeAvailability := instance.ServerTypesAvailability("unknown")
156+
name := pcuServerType.Properties.Instance.OfferID
157+
computeServerType := computeServerTypes.Servers[name]
158+
serverType := &customServerType{
159+
Name: name,
160+
HourlyPrice: pcuServerType.Price.RetailPrice,
161+
MaxFileSystems: computeServerType.Capabilities.MaxFileSystems,
162+
}
108163

109164
if availability, exists := availabilitiesResponse.Servers[name]; exists {
110-
serverTypeAvailability = availability.Availability
165+
serverType.Availability = availability.Availability
111166
}
112167

113-
serverTypes = append(serverTypes, &customServerType{
114-
Name: name,
115-
HourlyPrice: scw.NewMoneyFromFloat(
116-
float64(serverType.HourlyPrice),
117-
"EUR",
118-
3,
119-
),
120-
LocalVolumeMaxSize: serverType.VolumesConstraint.MaxSize,
121-
CPU: serverType.Ncpus,
122-
GPU: serverType.Gpu,
123-
RAM: scw.Size(serverType.RAM),
124-
Arch: serverType.Arch,
125-
Availability: serverTypeAvailability,
126-
MaxFileSystems: serverType.Capabilities.MaxFileSystems,
127-
})
128-
}
168+
if pcuServerType.Properties.Hardware != nil {
169+
if pcuServerType.Properties.Hardware.CPU != nil {
170+
serverType.CPU = pcuServerType.Properties.Hardware.CPU.Virtual.Count
171+
serverType.Arch = pcuServerType.Properties.Hardware.CPU.Arch.String()
172+
}
173+
174+
if pcuServerType.Properties.Hardware.Gpu != nil {
175+
serverType.GPU = pcuServerType.Properties.Hardware.Gpu.Count
176+
}
177+
178+
if pcuServerType.Properties.Hardware.RAM != nil {
179+
serverType.RAM = pcuServerType.Properties.Hardware.RAM.Size
180+
}
129181

130-
sort.Slice(serverTypes, func(i, j int) bool {
131-
categoryA := serverTypeCategory(serverTypes[i].Name)
132-
categoryB := serverTypeCategory(serverTypes[j].Name)
133-
if categoryA != categoryB {
134-
return categoryA < categoryB
182+
if pcuServerType.Properties.Hardware.Storage != nil {
183+
serverType.SupportedStorage = strings.Replace(
184+
pcuServerType.Properties.Hardware.Storage.Description,
185+
"Dynamic local: 1 x SSD",
186+
"Local",
187+
1,
188+
)
189+
}
190+
191+
if pcuServerType.Properties.Hardware.Network != nil {
192+
serverType.Bandwidth = scw.Size(
193+
pcuServerType.Properties.Hardware.Network.MaxPublicBandwidth,
194+
)
195+
}
135196
}
136197

137-
return serverTypes[i].HourlyPrice.ToFloat() < serverTypes[j].HourlyPrice.ToFloat()
138-
})
198+
serverTypes = append(serverTypes, serverType)
199+
}
139200

140201
return serverTypes, nil
141202
}
142203

143204
return c
144205
}
145206

146-
func serverTypeCategory(serverTypeName string) (category string) {
147-
return strings.Split(serverTypeName, "-")[0]
148-
}
149-
150207
func getCompatibleTypesBuilder(c *core.Command) *core.Command {
151208
c.Interceptor = func(ctx context.Context, argsI any, runner core.CommandRunner) (any, error) {
152209
rawResp, err := runner(ctx, argsI)
@@ -186,11 +243,10 @@ func getCompatibleTypesBuilder(c *core.Command) *core.Command {
186243
"EUR",
187244
3,
188245
),
189-
LocalVolumeMaxSize: serverType.VolumesConstraint.MaxSize,
190-
CPU: serverType.Ncpus,
191-
GPU: serverType.Gpu,
192-
RAM: scw.Size(serverType.RAM),
193-
Arch: serverType.Arch,
246+
CPU: serverType.Ncpus,
247+
GPU: uint32(*serverType.Gpu),
248+
RAM: scw.Size(serverType.RAM),
249+
Arch: serverType.Arch.String(),
194250
})
195251
}
196252

@@ -220,11 +276,10 @@ func getCompatibleTypesBuilder(c *core.Command) *core.Command {
220276
"EUR",
221277
3,
222278
),
223-
LocalVolumeMaxSize: currentServerType.VolumesConstraint.MaxSize,
224-
CPU: currentServerType.Ncpus,
225-
GPU: currentServerType.Gpu,
226-
RAM: scw.Size(currentServerType.RAM),
227-
Arch: currentServerType.Arch,
279+
CPU: currentServerType.Ncpus,
280+
GPU: uint32(*currentServerType.Gpu),
281+
RAM: scw.Size(currentServerType.RAM),
282+
Arch: currentServerType.Arch.String(),
228283
},
229284
}
230285

internal/namespaces/instance/v1/testdata/test-server-type-list-server-type-list.cassette.yaml

Lines changed: 195 additions & 156 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)