Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add GPU flavor list commands for baremetal and virtual GPU resources #171

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
39 changes: 39 additions & 0 deletions client/gpu/v3/commands.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package gpu

import (
"github.com/G-Core/gcorelabscloud-go/client/gpu/v3/flavors"
"github.com/G-Core/gcorelabscloud-go/client/gpu/v3/images"
"github.com/urfave/cli/v2"
)

var baremetalCommands = cli.Command{
Name: "baremetal",
Usage: "Manage baremetal GPU resources",
Description: "Commands for managing baremetal GPU resources",
Subcommands: []*cli.Command{
images.BaremetalCommands(),
flavors.BaremetalCommands(),
},
}

var virtualCommands = cli.Command{
Name: "virtual",
Usage: "Manage virtual GPU resources",
Description: "Commands for managing virtual GPU resources",
Subcommands: []*cli.Command{
images.VirtualCommands(),
flavors.VirtualCommands(),
},
}

// Commands returns the aggregated list of GPU commands
var Commands = cli.Command{
Name: "gpu",
Usage: "Manage GPU resources",
Description: "Parent command for GPU-related operations",
Category: "gpu",
Subcommands: []*cli.Command{
&baremetalCommands,
&virtualCommands,
},
}
108 changes: 108 additions & 0 deletions client/gpu/v3/flavors/commands.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package flavors

import (
gcorecloud "github.com/G-Core/gcorelabscloud-go"
"github.com/G-Core/gcorelabscloud-go/client/gpu/v3/client"
"github.com/G-Core/gcorelabscloud-go/client/utils"
"github.com/G-Core/gcorelabscloud-go/gcore/gpu/v3/flavors"
"github.com/urfave/cli/v2"
)

var listFlags = []cli.Flag{
&cli.BoolFlag{
Name: "include-prices",
Aliases: []string{"p"},
Usage: "Include prices in output",
Required: false,
},
&cli.BoolFlag{
Name: "exclude-disabled",
Aliases: []string{"ed"},
Usage: "Exclude disabled flavors (by default shows all flavors)",
Required: false,
},
}

// listFlavorsAction handles the common logic for listing both virtual and baremetal flavors
func listFlavorsAction(c *cli.Context, newClient func(*cli.Context) (*gcorecloud.ServiceClient, error)) error {
cl, err := newClient(c)
if err != nil {
_ = cli.ShowAppHelp(c)
return cli.Exit(err, 1)
}

includePrices := c.Bool("include-prices")
disabled := !c.Bool("exclude-disabled")
opts := flavors.ListOpts{
IncludePrices: &includePrices,
Disabled: &disabled,
}

results, err := flavors.List(cl, opts).AllPages()
if err != nil {
return cli.Exit(err, 1)
}

flavorList, err := flavors.ExtractFlavors(results)
if err != nil {
return cli.Exit(err, 1)
}
utils.ShowResults(flavorList, c.String("format"))
return nil
}

func listBaremetalFlavorsAction(c *cli.Context) error {
return listFlavorsAction(c, client.NewGPUBaremetalClientV3)
}

func listVirtualFlavorsAction(c *cli.Context) error {
return listFlavorsAction(c, client.NewGPUVirtualClientV3)
}

// BaremetalCommands returns commands for managing baremetal GPU flavors
func BaremetalCommands() *cli.Command {
return &cli.Command{
Name: "flavors",
Usage: "Manage baremetal GPU flavors",
Description: "Commands for managing baremetal GPU flavors",
Subcommands: []*cli.Command{
{
Name: "list",
Usage: "List baremetal GPU flavors",
Category: "flavors",
Flags: listFlags,
Action: listBaremetalFlavorsAction,
},
},
}
}

// VirtualCommands returns commands for managing virtual GPU flavors
func VirtualCommands() *cli.Command {
return &cli.Command{
Name: "flavors",
Usage: "Manage virtual GPU flavors",
Description: "Commands for managing virtual GPU flavors",
Subcommands: []*cli.Command{
{
Name: "list",
Usage: "List virtual GPU flavors",
Category: "flavors",
Flags: listFlags,
Action: listVirtualFlavorsAction,
},
},
}
}

// Commands returns the list of GPU flavor commands
var Commands = cli.Command{
Name: "gpu",
Usage: "Manage GPU resources",
Description: "Parent command for GPU-related operations",
Category: "gpu",
Subcommands: []*cli.Command{
BaremetalCommands(),
VirtualCommands(),
},
}
102 changes: 90 additions & 12 deletions client/gpu/v3/images/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,18 +184,6 @@ func stringPtr(s string) *string {
return &s
}

// Commands returns the list of GPU image commands
var Commands = cli.Command{
Name: "gpu",
Usage: "Manage GPU resources",
Description: "Parent command for GPU-related operations",
Category: "gpu",
Subcommands: []*cli.Command{
&baremetalCommand,
&virtualCommand,
},
}

// uploadImageAction handles the common logic for both virtual and baremetal image uploads
func uploadImageAction(c *cli.Context, newClient func(*cli.Context) (*gcorecloud.ServiceClient, error)) error {
if c.Args().Len() > 0 {
Expand Down Expand Up @@ -372,3 +360,93 @@ func showVirtualImageAction(c *cli.Context) error {
func showBaremetalImageAction(c *cli.Context) error {
return showImageAction(c, client.NewGPUBaremetalClientV3)
}

// BaremetalCommands returns commands for managing baremetal GPU images
func BaremetalCommands() *cli.Command {
return &cli.Command{
Name: "images",
Usage: "Manage baremetal GPU images",
Description: "Commands for managing baremetal GPU images",
Subcommands: []*cli.Command{
{
Name: "upload",
Usage: "Upload baremetal GPU image",
Description: "Upload a new baremetal GPU image with the specified URL and name",
Category: "images",
ArgsUsage: " ",
Flags: append(imageUploadFlags, flags.WaitCommandFlags...),
Action: uploadBaremetalImageAction,
},
{
Name: "list",
Usage: "List baremetal GPU images",
Description: "List all baremetal GPU images",
Category: "images",
ArgsUsage: " ",
Action: listBaremetalImagesAction,
},
{
Name: "show",
Usage: "Show baremetal GPU image details",
Description: "Show details of a specific baremetal GPU image",
Category: "images",
ArgsUsage: "<image_id>",
Action: showBaremetalImageAction,
},
{
Name: "delete",
Usage: "Delete baremetal GPU image",
Description: "Delete baremetal GPU image by ID",
Category: "images",
ArgsUsage: "<image_id>",
Flags: flags.WaitCommandFlags,
Action: deleteBaremetalImageAction,
},
},
}
}

// VirtualCommands returns commands for managing virtual GPU images
func VirtualCommands() *cli.Command {
return &cli.Command{
Name: "images",
Usage: "Manage virtual GPU images",
Description: "Commands for managing virtual GPU images",
Subcommands: []*cli.Command{
{
Name: "upload",
Usage: "Upload virtual GPU image",
Description: "Upload a new virtual GPU image with the specified URL and name",
Category: "images",
ArgsUsage: " ",
Flags: append(imageUploadFlags, flags.WaitCommandFlags...),
Action: uploadVirtualImageAction,
},
{
Name: "list",
Usage: "List virtual GPU images",
Description: "List all virtual GPU images",
Category: "images",
ArgsUsage: " ",
Action: listVirtualImagesAction,
},
{
Name: "show",
Usage: "Show virtual GPU image details",
Description: "Show details of a specific virtual GPU image",
Category: "images",
ArgsUsage: "<image_id>",
Action: showVirtualImageAction,
},
{
Name: "delete",
Usage: "Delete virtual GPU image",
Description: "Delete virtual GPU image by ID",
Category: "images",
ArgsUsage: "<image_id>",
Flags: flags.WaitCommandFlags,
Action: deleteVirtualImageAction,
},
},
}
}
4 changes: 2 additions & 2 deletions cmd/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
"github.com/G-Core/gcorelabscloud-go/client/flags"
"github.com/G-Core/gcorelabscloud-go/client/flavors/v1/flavors"
"github.com/G-Core/gcorelabscloud-go/client/floatingips/v1/floatingips"
gpuimages "github.com/G-Core/gcorelabscloud-go/client/gpu/v3/images"
"github.com/G-Core/gcorelabscloud-go/client/gpu/v3"
"github.com/G-Core/gcorelabscloud-go/client/heat"
"github.com/G-Core/gcorelabscloud-go/client/images/v1/images"
"github.com/G-Core/gcorelabscloud-go/client/instances/v1/instances"
Expand Down Expand Up @@ -80,7 +80,7 @@ var commands = []*cli.Command{
&file_shares.Commands,
&ais.Commands,
&functions.Commands,
&gpuimages.Commands,
&gpu.Commands,
}

type clientCommands struct {
Expand Down
41 changes: 41 additions & 0 deletions gcore/gpu/v3/flavors/requests.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package flavors

import (
gcorecloud "github.com/G-Core/gcorelabscloud-go"
"github.com/G-Core/gcorelabscloud-go/pagination"
)

// ListOptsBuilder allows extensions to add additional parameters to the List request.
type ListOptsBuilder interface {
ToFlavorListQuery() (string, error)
}

// ListOpts allows the filtering and sorting of paginated collections through the API.
type ListOpts struct {
IncludePrices *bool `q:"include_prices"`
Disabled *bool `q:"disabled"`
}

// ToFlavorListQuery formats a ListOpts into a query string.
func (opts ListOpts) ToFlavorListQuery() (string, error) {
q, err := gcorecloud.BuildQueryString(opts)
if err != nil {
return "", err
}
return q.String(), nil
}

// List retrieves list of GPU flavors
func List(client *gcorecloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
url := FlavorsURL(client)
if opts != nil {
query, err := opts.ToFlavorListQuery()
if err != nil {
return pagination.Pager{Err: err}
}
url += query
}
return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page {
return FlavorPage{pagination.LinkedPageBase{PageResult: r}}
})
}
77 changes: 77 additions & 0 deletions gcore/gpu/v3/flavors/results.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package flavors

import (
gcorecloud "github.com/G-Core/gcorelabscloud-go"
"github.com/G-Core/gcorelabscloud-go/pagination"
"github.com/shopspring/decimal"
)

type commonResult struct {
gcorecloud.Result
}

// GetResult represents the result of a get operation.
type GetResult struct {
commonResult
}

// PriceDisplayStatus represents the status of price display
type PriceDisplayStatus string

const (
PriceStatusShow PriceDisplayStatus = "show"
PriceStatusHide PriceDisplayStatus = "hide"
PriceStatusError PriceDisplayStatus = "error"
)

// Price represents a flavor price structure
type Price struct {
CurrencyCode *string `json:"currency_code"`
PricePerHour *decimal.Decimal `json:"price_per_hour"`
PricePerMonth *decimal.Decimal `json:"price_per_month"`
PriceStatus *PriceDisplayStatus `json:"price_status"`
}

// Flavor represents a GPU flavor
type Flavor struct {
ID string `json:"id"`
Name string `json:"name"`
VCPUs int `json:"vcpus"`
RAM int `json:"ram"`
Price *Price `json:"price"`
Architecture *string `json:"architecture"`
Disabled bool `json:"disabled"`
Capacity int `json:"capacity"`
HardwareDescription map[string]string `json:"hardware_description"`
}

// FlavorPage is the page returned by a pager when traversing over a collection of flavors.
type FlavorPage struct {
pagination.LinkedPageBase
}

// IsEmpty checks whether a FlavorPage struct is empty.
func (r FlavorPage) IsEmpty() (bool, error) {
flavors, err := ExtractFlavors(r)
return len(flavors) == 0, err
}

// ExtractFlavors accepts a Page struct, specifically a FlavorPage struct,
// and extracts the elements into a slice of Flavor structs.
func ExtractFlavors(r pagination.Page) ([]Flavor, error) {
var s []Flavor
err := ExtractFlavorsInto(r, &s)
return s, err
}

// ExtractFlavorsInto similar to ExtractInto but operates on a List of Flavors
func ExtractFlavorsInto(r pagination.Page, v interface{}) error {
return r.(FlavorPage).Result.ExtractIntoSlicePtr(v, "results")
}

// Extract will get the Flavor object from the commonResult
func (r commonResult) Extract() (*Flavor, error) {
var s Flavor
err := r.ExtractInto(&s)
return &s, err
}
Loading