Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 92 additions & 0 deletions cmd/bcloud/commands/create.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package commands

import (
"context"
"fmt"

"github.com/brevdev/cloud/cmd/bcloud/config"
v1 "github.com/brevdev/cloud/pkg/v1"
"github.com/spf13/cobra"
"gopkg.in/yaml.v3"
)

var createCmd = &cobra.Command{
Use: "create <refId>",
Short: "Create a new instance",
Args: cobra.ExactArgs(1),
RunE: runCreate,
}

var (
instanceType string
location string
name string
imageID string
publicKey string
)

func init() {
createCmd.Flags().StringVar(&instanceType, "instance-type", "", "Instance type to create")
createCmd.Flags().StringVar(&location, "location", "", "Location to create instance in")
createCmd.Flags().StringVar(&name, "name", "", "Name for the instance")
createCmd.Flags().StringVar(&imageID, "image-id", "", "Image ID to use")
createCmd.Flags().StringVar(&publicKey, "public-key", "", "SSH public key")

if err := createCmd.MarkFlagRequired("instance-type"); err != nil {
panic(err)
}
}

func runCreate(_ *cobra.Command, args []string) error {
if cfg == nil {
return fmt.Errorf("configuration not loaded")
}

refID := args[0]

credEntry, exists := cfg.Credentials[refID]
if !exists {
return fmt.Errorf("credential '%s' not found in config", refID)
}

cred := credEntry.Value
if cred == nil {
return fmt.Errorf("credential entry has no value")
}

if location == "" {
if provider, ok := cred.(config.DefaultLocationProvider); ok {
location = provider.GetDefaultLocation()
}
}
if location == "" {
return fmt.Errorf("location is required (use --location or set default_location in config)")
}

ctx := context.Background()
client, err := cred.MakeClient(ctx, location)
if err != nil {
return fmt.Errorf("failed to create client: %w", err)
}

attrs := v1.CreateInstanceAttrs{
Location: location,
Name: name,
InstanceType: instanceType,
ImageID: imageID,
PublicKey: publicKey,
}

instance, err := client.CreateInstance(ctx, attrs)
if err != nil {
return fmt.Errorf("failed to create instance: %w", err)
}

output, err := yaml.Marshal(instance)
if err != nil {
return fmt.Errorf("failed to marshal output: %w", err)
}

fmt.Print(string(output))
return nil
}
64 changes: 64 additions & 0 deletions cmd/bcloud/commands/get.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package commands

import (
"context"
"fmt"

"github.com/brevdev/cloud/cmd/bcloud/config"
v1 "github.com/brevdev/cloud/pkg/v1"
"github.com/spf13/cobra"
"gopkg.in/yaml.v3"
)

var getCmd = &cobra.Command{
Use: "get <refId> <instanceId>",
Short: "Get instance details",
Args: cobra.ExactArgs(2),
RunE: runGet,
}

func runGet(_ *cobra.Command, args []string) error {
if cfg == nil {
return fmt.Errorf("configuration not loaded")
}

refID := args[0]
instanceID := v1.CloudProviderInstanceID(args[1])

credEntry, exists := cfg.Credentials[refID]
if !exists {
return fmt.Errorf("credential '%s' not found in config", refID)
}

cred := credEntry.Value
if cred == nil {
return fmt.Errorf("credential entry has no value")
}

var defaultLocation string
if provider, ok := cred.(config.DefaultLocationProvider); ok {
defaultLocation = provider.GetDefaultLocation()
}
if defaultLocation == "" {
return fmt.Errorf("default location is required in config")
}

ctx := context.Background()
client, err := cred.MakeClient(ctx, defaultLocation)
if err != nil {
return fmt.Errorf("failed to create client: %w", err)
}

instance, err := client.GetInstance(ctx, instanceID)
if err != nil {
return fmt.Errorf("failed to get instance: %w", err)
}

output, err := yaml.Marshal(instance)
if err != nil {
return fmt.Errorf("failed to marshal output: %w", err)
}

fmt.Print(string(output))
return nil
}
72 changes: 72 additions & 0 deletions cmd/bcloud/commands/list.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package commands

import (
"context"
"fmt"

"github.com/brevdev/cloud/cmd/bcloud/config"
v1 "github.com/brevdev/cloud/pkg/v1"
"github.com/spf13/cobra"
"gopkg.in/yaml.v3"
)

var listCmd = &cobra.Command{
Use: "list <refId>",
Short: "List instances",
Args: cobra.ExactArgs(1),
RunE: runList,
}

var listLocation string

func init() {
listCmd.Flags().StringVar(&listLocation, "location", "", "Location to list instances from")
}

func runList(_ *cobra.Command, args []string) error {
if cfg == nil {
return fmt.Errorf("configuration not loaded")
}

refID := args[0]

credEntry, exists := cfg.Credentials[refID]
if !exists {
return fmt.Errorf("credential '%s' not found in config", refID)
}

cred := credEntry.Value
if cred == nil {
return fmt.Errorf("credential entry has no value")
}

if listLocation == "" {
if provider, ok := cred.(config.DefaultLocationProvider); ok {
listLocation = provider.GetDefaultLocation()
}
}
if listLocation == "" {
return fmt.Errorf("location is required (use --location or set default_location in config)")
}

ctx := context.Background()
client, err := cred.MakeClient(ctx, listLocation)
if err != nil {
return fmt.Errorf("failed to create client: %w", err)
}

instances, err := client.ListInstances(ctx, v1.ListInstancesArgs{
Locations: []string{listLocation},
})
if err != nil {
return fmt.Errorf("failed to list instances: %w", err)
}

output, err := yaml.Marshal(instances)
if err != nil {
return fmt.Errorf("failed to marshal output: %w", err)
}

fmt.Print(string(output))
return nil
}
44 changes: 44 additions & 0 deletions cmd/bcloud/commands/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package commands

import (
"fmt"

"github.com/brevdev/cloud/cmd/bcloud/config"
"github.com/spf13/cobra"
)

var (
cfgFile string
cfg *config.Config
)

var rootCmd = &cobra.Command{
Use: "bcloud <refId> <verb>",
Short: "Brev Cloud CLI for managing GPU compute across providers",
Long: `A vendor-agnostic CLI for managing clusterable, GPU-accelerated compute
across multiple cloud providers using the Brev Cloud SDK.`,
}

func Execute() error {
return rootCmd.Execute()
}

func init() {
cobra.OnInitialize(initConfig)
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is ~/.bcloud/credentials.yaml)")

rootCmd.AddCommand(createCmd)
rootCmd.AddCommand(terminateCmd)
rootCmd.AddCommand(listCmd)
rootCmd.AddCommand(getCmd)
rootCmd.AddCommand(typesCmd)
}

func initConfig() {
var err error
cfg, err = config.LoadConfig()
if err != nil {
fmt.Printf("Error loading config: %v\n", err)
fmt.Println("Create ~/.bcloud/credentials.yaml with your cloud credentials")
}
}
58 changes: 58 additions & 0 deletions cmd/bcloud/commands/terminate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package commands

import (
"context"
"fmt"

"github.com/brevdev/cloud/cmd/bcloud/config"
v1 "github.com/brevdev/cloud/pkg/v1"
"github.com/spf13/cobra"
)

var terminateCmd = &cobra.Command{
Use: "terminate <refId> <instanceId>",
Short: "Terminate an instance",
Args: cobra.ExactArgs(2),
RunE: runTerminate,
}

func runTerminate(_ *cobra.Command, args []string) error {
if cfg == nil {
return fmt.Errorf("configuration not loaded")
}

refID := args[0]
instanceID := v1.CloudProviderInstanceID(args[1])

credEntry, exists := cfg.Credentials[refID]
if !exists {
return fmt.Errorf("credential '%s' not found in config", refID)
}

cred := credEntry.Value
if cred == nil {
return fmt.Errorf("credential value is nil")
}

var defaultLocation string
if provider, ok := cred.(config.DefaultLocationProvider); ok {
defaultLocation = provider.GetDefaultLocation()
}
if defaultLocation == "" {
return fmt.Errorf("default location is required in config")
}

ctx := context.Background()
client, err := cred.MakeClient(ctx, defaultLocation)
if err != nil {
return fmt.Errorf("failed to create client: %w", err)
}

err = client.TerminateInstance(ctx, instanceID)
if err != nil {
return fmt.Errorf("failed to terminate instance: %w", err)
}

fmt.Printf("Instance %s terminated successfully\n", instanceID)
return nil
}
Loading