Skip to content

Commit

Permalink
Add fixes for ai client (#86)
Browse files Browse the repository at this point in the history
Co-authored-by: Ivan Denezhkin <idenezhkin@itkey.com>
  • Loading branch information
pikwick and pikwick authored Oct 23, 2023
1 parent 8e62c87 commit 7b3e49f
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 83 deletions.
105 changes: 58 additions & 47 deletions client/ais/v1/ais/ias.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
client2 "github.com/G-Core/gcorelabscloud-go/client/ais/v2/client"
"github.com/G-Core/gcorelabscloud-go/client/flags"
instance_client "github.com/G-Core/gcorelabscloud-go/client/instances/v1/instances"
task_client "github.com/G-Core/gcorelabscloud-go/client/tasks/v1/client"
"github.com/G-Core/gcorelabscloud-go/client/utils"
cmeta "github.com/G-Core/gcorelabscloud-go/client/utils/metadata"
"github.com/G-Core/gcorelabscloud-go/gcore/ai/v1/aiflavors"
Expand Down Expand Up @@ -220,23 +221,6 @@ var aiClusterAttachInterfacesCommand = cli.Command{
Usage: "interface port id",
Required: false,
},
&cli.StringFlag{
Name: "ip-address",
Aliases: []string{"ip"},
Usage: "interface ip address id",
Required: false,
},
&cli.StringFlag{
Name: "floating-type",
Usage: "interface ip address id",
Required: false,
},
&cli.StringFlag{
Name: "floating-id",
Aliases: []string{"fip"},
Usage: "floating ip id for interface",
Required: false,
},
},
),
Action: func(c *cli.Context) error {
Expand All @@ -250,23 +234,12 @@ var aiClusterAttachInterfacesCommand = cli.Command{
_ = cli.ShowAppHelp(c)
return cli.NewExitError(err, 1)
}
var fipOpts *instances.CreateNewInterfaceFloatingIPOpts
fipSource := types.FloatingIPSource(c.String("floating-type"))
fipID := c.String("floating-id")
if fipSource != "" || fipID != "" {
fipOpts = &instances.CreateNewInterfaceFloatingIPOpts{
Source: fipSource,
ExistingFloatingID: fipID,
}
}

opts := ai.AttachInterfaceOpts{
Type: types.InterfaceType(c.String("type")),
NetworkID: c.String("network"),
SubnetID: c.String("subnet"),
PortID: c.String("port"),
IpAddress: c.String("ip-address"),
FloatingIP: fipOpts,
Type: types.InterfaceType(c.String("type")),
NetworkID: c.String("network"),
SubnetID: c.String("subnet"),
PortID: c.String("port"),
}

results, err := ai.AttachAIInstanceInterface(client, instanceID, opts).Extract()
Expand Down Expand Up @@ -375,7 +348,7 @@ var aiClusterAssignSecurityGroupsCommand = cli.Command{

opts := instances.SecurityGroupOpts{Name: c.String("name")}

err = instances.AssignSecurityGroup(client, clusterID, opts).ExtractErr()
err = ai.AssignSecurityGroup(client, clusterID, opts).ExtractErr()
if err != nil {
return cli.NewExitError(err, 1)
}
Expand Down Expand Up @@ -410,7 +383,7 @@ var aiClusterUnAssignSecurityGroupsCommand = cli.Command{

opts := instances.SecurityGroupOpts{Name: c.String("name")}

err = instances.UnAssignSecurityGroup(client, instanceID, opts).ExtractErr()
err = ai.UnAssignSecurityGroup(client, instanceID, opts).ExtractErr()
if err != nil {
return cli.NewExitError(err, 1)
}
Expand Down Expand Up @@ -575,9 +548,27 @@ var aiClusterCreateCommand = cli.Command{
Usage: "instance metadata. Example: --metadata one=two --metadata three=four",
Required: false,
},
&cli.BoolFlag{
Name: "gpu",
Usage: "create gpu cluster else not gpu cluster",
Required: false,
},
}, flags.WaitCommandFlags...),
Action: func(c *cli.Context) error {
client, err := client.NewAIClusterClientV1(c)
clusterClient, err := client.NewAIClusterClientV1(c)
if err != nil {
_ = cli.ShowAppHelp(c)
return cli.NewExitError(err, 1)
}
if c.Bool("gpu") {
clusterClient, err = client.NewAIGPUClusterClientV1(c)
if err != nil {
_ = cli.ShowAppHelp(c)
return cli.NewExitError(err, 1)
}
}

clusterClientV2, err := client2.NewAIClusterClientV2(c)
if err != nil {
_ = cli.ShowAppHelp(c)
return cli.NewExitError(err, 1)
Expand Down Expand Up @@ -629,21 +620,25 @@ var aiClusterCreateCommand = cli.Command{
return cli.NewExitError(err, 1)
}

results, err := ai.Create(client, opts).Extract()
results, err := ai.Create(clusterClient, opts).Extract()
if err != nil {
return cli.NewExitError(err, 1)
}

return utils.WaitTaskAndShowResult(c, client, results, true, func(task tasks.TaskID) (interface{}, error) {
taskInfo, err := tasks.Get(client, string(task)).Extract()
taskClient, err := task_client.NewTaskClientV1(c)
if err != nil {
_ = cli.ShowAppHelp(c)
return cli.NewExitError(err, 1)
}
return utils.WaitTaskAndShowResult(c, taskClient, results, true, func(task tasks.TaskID) (interface{}, error) {
taskInfo, err := tasks.Get(taskClient, string(task)).Extract()
if err != nil {
return nil, fmt.Errorf("cannot get task with ID: %s. Error: %w", task, err)
}
clusterID, err := ai.ExtractAIClusterIDFromTask(taskInfo)
if err != nil {
return nil, fmt.Errorf("cannot retrieve AI cluster ID from task info: %w", err)
}
cluster, err := ai.Get(client, clusterID).Extract()
cluster, err := ai.Get(clusterClientV2, clusterID).Extract()
if err != nil {
return nil, fmt.Errorf("cannot get AI cluster with ID: %s. Error: %w", clusterID, err)
}
Expand All @@ -658,7 +653,7 @@ var aiClusterResizeCommand = cli.Command{
Resize AI cluster
Example: token ai resize --flavor g2a-ai-fake-v1pod-8 --image 06e62653-1f88-4d38-9aa6-62833e812b4f --keypair sshkey --it any_subnet --interface-network-id 518ba531-496b-4676-8ea4-68e2ed3b2e4b --interface-floating-source new --volume-type standard --volume-source image --volume-image-id 06e62653-1f88-4d38-9aa6-62833e812b4f --volume-size 20 e673bba0-fcef-44d9-904c-824546b608ec -d -w`,
ArgsUsage: "<cluster_id>",
Category: "cluster",
Category: "cluster",
Flags: append([]cli.Flag{
&cli.StringFlag{
Name: "flavor",
Expand Down Expand Up @@ -943,7 +938,13 @@ var aiClusterDeleteCommand = cli.Command{
return cli.NewExitError(err, 1)
}

return utils.WaitTaskAndShowResult(c, client, results, false, func(task tasks.TaskID) (interface{}, error) {
taskClient, err := task_client.NewTaskClientV1(c)
if err != nil {
_ = cli.ShowAppHelp(c)
return cli.NewExitError(err, 1)
}

return utils.WaitTaskAndShowResult(c, taskClient, results, false, func(task tasks.TaskID) (interface{}, error) {
_, err := ai.Get(client, clusterID).Extract()
if err == nil {
return nil, fmt.Errorf("cannot delete AI cluster with ID: %s", clusterID)
Expand Down Expand Up @@ -1157,18 +1158,30 @@ var aiClusterAvailableImagesCommand = cli.Command{
Usage: fmt.Sprintf("image visibility type. output in %s", strings.Join(visibilityTypes, ", ")),
Required: false,
},
&cli.BoolFlag{
Name: "gpu",
Usage: "only gpu images or not gpu images",
Required: false,
},
},
Action: func(c *cli.Context) error {
client, err := client.NewAIImageClientV1(c)
imageClient, err := client.NewAIImageClientV1(c)
if err != nil {
_ = cli.ShowAppHelp(c)
return cli.NewExitError(err, 1)
}
if c.Bool("gpu") {
imageClient, err = client.NewAIGPUImageClientV1(c)
if err != nil {
_ = cli.ShowAppHelp(c)
return cli.NewExitError(err, 1)
}
}
opts := aiimages.AIImageListOpts{
Visibility: c.String("visibility"),
Private: c.String("private"),
}
images, err := aiimages.ListAll(client, opts)
images, err := aiimages.ListAll(imageClient, opts)
if err != nil {
return cli.NewExitError(err, 1)
}
Expand All @@ -1177,7 +1190,6 @@ var aiClusterAvailableImagesCommand = cli.Command{
},
}


var aiClusterAvailableFlavorsCommand = cli.Command{
Name: "list",
Usage: "List flavors available for AI cluser",
Expand All @@ -1198,7 +1210,6 @@ var aiClusterAvailableFlavorsCommand = cli.Command{
Usage: "show flavor price",
Required: false,
},

},
Action: func(c *cli.Context) error {
client, err := client.NewAIFlavorClientV1(c)
Expand All @@ -1218,4 +1229,4 @@ var aiClusterAvailableFlavorsCommand = cli.Command{
utils.ShowResults(flavors, c.String("format"))
return nil
},
}
}
13 changes: 9 additions & 4 deletions client/ais/v1/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,18 @@ func NewAIClusterClientV1(c *cli.Context) (*gcorecloud.ServiceClient, error) {
return common.BuildClient(c, "ai/clusters", "v1")
}

func NewAIGPUClusterClientV1(c *cli.Context) (*gcorecloud.ServiceClient, error) {
return common.BuildClient(c, "ai/clusters/gpu", "v1")
}

func NewAIImageClientV1(c *cli.Context) (*gcorecloud.ServiceClient, error) {
return common.BuildClient(c, "ai/images", "v1")
}

func NewAIGPUImageClientV1(c *cli.Context) (*gcorecloud.ServiceClient, error) {
return common.BuildClient(c, "ai/images/gpu", "v1")
}

func NewAIFlavorClientV1(c *cli.Context) (*gcorecloud.ServiceClient, error) {
return common.BuildClient(c, "ai/flavors", "v1")
}




13 changes: 5 additions & 8 deletions gcore/ai/v1/aiimages/requests.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,21 @@ import (
"github.com/G-Core/gcorelabscloud-go/pagination"
)


type VisibilityType string

const (
PRIVATE VisibilityType = "private"
PUBLIC VisibilityType = "public"
SHARED VisibilityType = "shared"
PUBLIC VisibilityType = "public"
SHARED VisibilityType = "shared"
)

type ListOptsBuilder interface {
ToAIImageListQuery() (string, error)
}

type AIImageListOpts struct {
Visibility string `q:"visibility" validate:"omitempty,enum"`
Private string `q:"private" validate:"omitempty"`
Visibility string `q:"visibility" validate:"omitempty,enum"`
Private string `q:"private" validate:"omitempty"`
MetadataK string `q:"metadata_k" validate:"omitempty"`
MetadataKV map[string]string `q:"metadata_kv" validate:"omitempty"`
}
Expand All @@ -34,8 +33,6 @@ func (opts AIImageListOpts) ToAIImageListQuery() (string, error) {
return q.String(), err
}



// List retrieves list of flavors
func List(c *gcorecloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
url := listAIImagesURL(c)
Expand All @@ -58,4 +55,4 @@ func ListAll(c *gcorecloud.ServiceClient, opts ListOptsBuilder) ([]AIImage, erro
return nil, err
}
return ExtractAIImages(results)
}
}
15 changes: 0 additions & 15 deletions gcore/ai/v1/aiimages/results.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,6 @@ import (
"github.com/G-Core/gcorelabscloud-go/pagination"
)

type commonResult struct {
gcorecloud.Result
}

// Extract is a function that accepts a result and extracts a instance resource.
func (r commonResult) Extract() (*AIImage, error) {
var s AIImage
err := r.ExtractInto(&s)
return &s, err
}

func (r commonResult) ExtractInto(v interface{}) error {
return r.Result.ExtractIntoStructPtr(v, "")
}

// AIFlavorPage is the page returned by a pager when traversing over a
// collection of instances.
type AIImagePage struct {
Expand Down
15 changes: 7 additions & 8 deletions gcore/ai/v1/ais/requests.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ type CreateOpts struct {
Name string `json:"name" validate:"required,min=3,max=63"`
ImageID string `json:"image_id" validate:"required,uuid4"`
Interfaces []instances.InterfaceInstanceCreateOpts `json:"interfaces" validate:"required,dive"`
Volumes []instances.CreateVolumeOpts `json:"volumes" validate:"required,dive"`
Volumes []instances.CreateVolumeOpts `json:"volumes,omitempty" validate:"omitempty,required,dive"`
SecurityGroups []gcorecloud.ItemID `json:"security_groups,omitempty" validate:"omitempty,dive,uuid4"`
Keypair string `json:"keypair_name,omitempty"`
Password string `json:"password" validate:"omitempty,required_with=Username"`
Expand Down Expand Up @@ -87,7 +87,7 @@ type ResizeAIClusterOpts struct {
Flavor string `json:"flavor" validate:"omitempty,min=1"`
ImageID string `json:"image_id" validate:"omitempty,uuid4"`
Interfaces []instances.InterfaceInstanceCreateOpts `json:"interfaces" validate:"required,dive"`
Volumes []instances.CreateVolumeOpts `json:"volumes" validate:"omitempty,dive"`
Volumes []instances.CreateVolumeOpts `json:"volumes,omitempty" validate:"omitempty,dive"`
SecurityGroups []gcorecloud.ItemID `json:"security_groups,omitempty" validate:"omitempty,dive,uuid4"`
Keypair string `json:"keypair_name,omitempty"`
Password string `json:"password" validate:"omitempty,required_with=Username"`
Expand Down Expand Up @@ -119,12 +119,11 @@ type AttachInterfaceOptsBuilder interface {
}

type AttachInterfaceOpts struct {
Type types.InterfaceType `json:"type,omitempty" validate:"omitempty,enum"`
NetworkID string `json:"network_id,omitempty" validate:"rfe=Type:any_subnet,omitempty,uuid4"`
SubnetID string `json:"subnet_id,omitempty" validate:"rfe=Type:subnet,omitempty,uuid4"`
PortID string `json:"port_id,omitempty" validate:"rfe=Type:reserved_fixed_ip,allowed_without_all=NetworkID SubnetID,omitempty,uuid4"`
IpAddress string `json:"ip_address,omitempty" validate:"allowed_without_all=Type NetworkID SubnetID FloatingIP,omitempty"`
FloatingIP *instances.CreateNewInterfaceFloatingIPOpts `json:"floating_ip,omitempty" validate:"omitempty,dive"`
Type types.InterfaceType `json:"type,omitempty" validate:"omitempty,enum"`
NetworkID string `json:"network_id,omitempty" validate:"rfe=Type:any_subnet,omitempty,uuid4"`
SubnetID string `json:"subnet_id,omitempty" validate:"rfe=Type:subnet,omitempty,uuid4"`
PortID string `json:"port_id,omitempty" validate:"rfe=Type:reserved_fixed_ip,allowed_without_all=NetworkID SubnetID,omitempty,uuid4"`
IpAddress string `json:"ip_address,omitempty" validate:"allowed_without_all=Type NetworkID SubnetID FloatingIP,omitempty"`
}

// Validate
Expand Down
2 changes: 1 addition & 1 deletion gcore/ai/v1/ais/results.go
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ func (i *AICluster) UnmarshalJSON(data []byte) error {
}

type AIClusterTaskResult struct {
AIClusters []string `json:"ai_clusters"`
AIClusters []string `mapstructure:"ai_clusters"`
// etc
}

Expand Down

0 comments on commit 7b3e49f

Please sign in to comment.