Skip to content

Commit

Permalink
add ListLabs and other things
Browse files Browse the repository at this point in the history
  • Loading branch information
Pavel Anni committed Nov 30, 2024
1 parent 0556c5b commit 572db27
Show file tree
Hide file tree
Showing 16 changed files with 264 additions and 120 deletions.
1 change: 1 addition & 0 deletions cmd/create-lab.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ func createLab(lab *types.Lab) (*types.Lab, error) {
},
Spec: types.ServerSpec{
Location: lab.Spec.Location,
Provider: lab.Spec.Provider,
Type: serverSpec.Type,
TTL: ttl,
Image: serverSpec.Image,
Expand Down
2 changes: 2 additions & 0 deletions cmd/create-server.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ func NewCreateServerCmd() *cobra.Command {
Type: serverType,
Image: image,
Location: location,
Provider: cfg.Provider.Name,
SSHKeyNames: sshKeyNames,
},
}
Expand Down Expand Up @@ -122,6 +123,7 @@ func createServer(server *types.Server) (*types.Server, error) {
Type: server.Spec.Type,
Image: server.Spec.Image,
Location: server.Spec.Location,
Provider: server.Spec.Provider,
SSHKeys: sshKeys,
Labels: labels,
UserData: cloudInitUserData,
Expand Down
81 changes: 25 additions & 56 deletions cmd/get-lab.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import (
"text/tabwriter"
"time"

"github.com/pavelanni/labshop/internal/types"
"github.com/pavelanni/labshop/internal/provider/options"
"github.com/pavelanni/labshop/internal/util/output"
"github.com/pavelanni/labshop/internal/util/timeutil"
"github.com/spf13/cobra"
)
Expand All @@ -29,52 +30,10 @@ func NewGetLabCmd() *cobra.Command {
}

func listLabs() error {
labs := make(map[string]*types.Lab)
servers, err := providerSvc.AllServers()
labs, err := providerSvc.ListLabs(options.LabListOpts{})
if err != nil {
return err
}
volumes, err := providerSvc.AllVolumes()
if err != nil {
return err
}
for _, server := range servers {
labName := server.Labels["lab_name"]
if labName == "" {
continue
}
if labs[labName] == nil {
labs[labName] = &types.Lab{
TypeMeta: types.TypeMeta{
APIVersion: "v1",
Kind: "Lab",
},
ObjectMeta: types.ObjectMeta{
Name: labName,
},
}
}
labs[labName].Status.Servers = append(labs[labName].Status.Servers, server)
}
for _, volume := range volumes {
labName := volume.Labels["lab_name"]
if labName == "" {
continue
}
if labs[labName] == nil {
labs[labName] = &types.Lab{
TypeMeta: types.TypeMeta{
APIVersion: "v1",
Kind: "Lab",
},
ObjectMeta: types.ObjectMeta{
Name: labName,
},
}
}
labs[labName].Status.Volumes = append(labs[labName].Status.Volumes, volume)
}

// Create a new tabwriter
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)

Expand Down Expand Up @@ -119,18 +78,28 @@ func getLab(labName string) error {
if err != nil {
return err
}
fmt.Printf("Lab: %s\n", lab.Name)
for _, server := range lab.Status.Servers {
fmt.Printf(" Server: %s, Type: %s, Cores: %d, Memory: %.2fGB, Disk: %dGB, DeleteAfter: %s\n",
server.ObjectMeta.Name,
server.Spec.Type,
server.Status.Cores,
server.Status.Memory,
server.Status.Disk,
server.Status.DeleteAfter)
}
for _, volume := range lab.Status.Volumes {
fmt.Printf(" Volume: %s, Size: %dGB, DeleteAfter: %s\n", volume.ObjectMeta.Name, volume.Spec.Size, volume.Status.DeleteAfter)
switch cfg.OutputFormat {
case "json":
return output.JSON(lab)
case "yaml":
return output.YAML(lab)
default:
fmt.Printf("Lab: %s\n", lab.Name)
for _, server := range lab.Status.Servers {
fmt.Printf(" Server: %s, Type: %s, Cores: %d, Memory: %.2fGB, Disk: %dGB, DeleteAfter: %s\n",
server.ObjectMeta.Name,
server.Spec.Type,
server.Status.Cores,
server.Status.Memory,
server.Status.Disk,
server.Status.DeleteAfter)
}
for _, volume := range lab.Status.Volumes {
fmt.Printf(" Volume: %s, Size: %dGB, DeleteAfter: %s\n",
volume.ObjectMeta.Name,
volume.Spec.Size,
volume.Status.DeleteAfter)
}
}

return nil
Expand Down
32 changes: 20 additions & 12 deletions cmd/get-server.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"text/tabwriter"
"time"

"github.com/pavelanni/labshop/internal/util/output"
"github.com/pavelanni/labshop/internal/util/timeutil"
"github.com/spf13/cobra"
)
Expand Down Expand Up @@ -56,17 +57,24 @@ func getServer(serverID string) error {
return err
}

w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
fmt.Fprintln(w, "NAME\tTYPE\tOWNER\tAGE\tDELETE AFTER")
deleteAfter := "-"
if !server.Status.DeleteAfter.IsZero() {
deleteAfter = server.Status.DeleteAfter.Format(time.RFC3339)
switch cfg.OutputFormat {
case "json":
return output.JSON(server)
case "yaml":
return output.YAML(server)
default:
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
fmt.Fprintln(w, "NAME\tTYPE\tOWNER\tAGE\tDELETE AFTER")
deleteAfter := "-"
if !server.Status.DeleteAfter.IsZero() {
deleteAfter = server.Status.DeleteAfter.Format(time.RFC3339)
}
fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n",
server.Name,
server.Spec.Type,
server.Status.Owner,
timeutil.FormatAge(server.Status.Created),
deleteAfter)
return w.Flush()
}
fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n",
server.Name,
server.Spec.Type,
server.Status.Owner,
timeutil.FormatAge(server.Status.Created),
deleteAfter)
return w.Flush()
}
34 changes: 21 additions & 13 deletions cmd/get-volume.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"text/tabwriter"
"time"

"github.com/pavelanni/labshop/internal/util/output"
"github.com/pavelanni/labshop/internal/util/timeutil"
"github.com/spf13/cobra"
)
Expand Down Expand Up @@ -57,18 +58,25 @@ func getVolume(volumeID string) error {
return err
}

w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
fmt.Fprintln(w, "NAME\tSERVER\tSIZE\tOWNER\tAGE\tDELETE AFTER")
deleteAfter := "-"
if !volume.Status.DeleteAfter.IsZero() {
deleteAfter = volume.Status.DeleteAfter.Format(time.RFC3339)
switch cfg.OutputFormat {
case "json":
return output.JSON(volume)
case "yaml":
return output.YAML(volume)
default:
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
fmt.Fprintln(w, "NAME\tSERVER\tSIZE\tOWNER\tAGE\tDELETE AFTER")
deleteAfter := "-"
if !volume.Status.DeleteAfter.IsZero() {
deleteAfter = volume.Status.DeleteAfter.Format(time.RFC3339)
}
fmt.Fprintf(w, "%s\t%s\t%d\t%s\t%s\t%s\n",
volume.Name,
volume.Spec.ServerName,
volume.Spec.Size,
volume.Status.Owner,
timeutil.FormatAge(volume.Status.Created),
deleteAfter)
return w.Flush()
}
fmt.Fprintf(w, "%s\t%s\t%d\t%s\t%s\t%s\n",
volume.Name,
volume.Spec.ServerName,
volume.Spec.Size,
volume.Status.Owner,
timeutil.FormatAge(volume.Status.Created),
deleteAfter)
return w.Flush()
}
2 changes: 2 additions & 0 deletions cmd/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,7 @@ func NewGetCmd() *cobra.Command {
cmd.AddCommand(NewGetVolumeCmd())
cmd.AddCommand(NewGetKeyCmd())

cmd.PersistentFlags().StringVarP(&cfg.OutputFormat, "output", "o", "text", "Output format (text|json|yaml)")

return cmd
}
13 changes: 4 additions & 9 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,6 @@ func NewRootCmd() *cobra.Command {
Use: "labshop",
Short: "Labshop - Lab Environment Manager",
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
// Skip initialization for the init command
if cmd.Name() == "init" {
return nil
}

// Initialize everything before command execution
initConfig()
initProvider()
initDNS()
return nil
},
}
Expand All @@ -47,6 +38,10 @@ func NewRootCmd() *cobra.Command {

// Only add other commands if not running 'init'
if len(os.Args) > 1 && os.Args[1] != "init" {
// Initialize everything before adding other commands
initConfig()
initProvider()
initDNS()
cmd.AddCommand(
NewGetCmd(),
NewDeleteCmd(),
Expand Down
2 changes: 2 additions & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ type Config struct {
Email string `mapstructure:"email" yaml:"email"`
Organization string `mapstructure:"organization" yaml:"organization"`
Owner string `mapstructure:"owner" yaml:"owner"`
Debug bool
OutputFormat string
}

type ProviderConfig struct {
Expand Down
59 changes: 43 additions & 16 deletions internal/provider/hetzner/lab.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package hetzner

import (
"github.com/pavelanni/labshop/internal/provider/options"
"github.com/pavelanni/labshop/internal/types"
)

Expand All @@ -19,32 +20,58 @@ func (p *HetznerProvider) GetLab(labName string) (*types.Lab, error) {
},
}

servers, err := p.AllServers()
servers, err := p.ListServers(options.ServerListOpts{
ListOpts: options.ListOpts{
LabelSelector: "lab_name=" + labName,
},
})
if err != nil {
return nil, err
}
volumes, err := p.AllVolumes()
volumes, err := p.ListVolumes(options.VolumeListOpts{
ListOpts: options.ListOpts{
LabelSelector: "lab_name=" + labName,
},
})
if err != nil {
return nil, err
}
for _, server := range servers {
labName := server.Labels["lab_name"]
if labName == "" {
continue
}
if labName != lab.Name {
continue
lab.Status.Servers = append(lab.Status.Servers, servers...)
lab.Status.Volumes = append(lab.Status.Volumes, volumes...)
// Add labels from the first server
if len(servers) > 0 {
lab.ObjectMeta.Labels = servers[0].ObjectMeta.Labels
}
lab.Status.Status = servers[0].Status.Status
lab.Status.Owner = servers[0].Status.Owner
lab.Status.Created = servers[0].Status.Created
lab.Status.DeleteAfter = servers[0].Status.DeleteAfter
lab.Spec.Location = servers[0].Spec.Location
lab.Spec.Provider = servers[0].Spec.Provider
return lab, nil
}

func (p *HetznerProvider) ListLabs(opts options.LabListOpts) ([]*types.Lab, error) {
labsMap := make(map[string]*types.Lab)
allServers, err := p.AllServers()
if err != nil {
return nil, err
}
// collect unique lab names
for _, server := range allServers {
if server.Labels["lab_name"] != "" {
labsMap[server.Labels["lab_name"]] = &types.Lab{}
}
lab.Status.Servers = append(lab.Status.Servers, server)
}
for _, volume := range volumes {
labName := volume.Labels["lab_name"]
if labName != lab.Name {
continue
labs := make([]*types.Lab, 0)
for labName := range labsMap {
lab, err := p.GetLab(labName)
if err != nil {
return nil, err
}
lab.Status.Volumes = append(lab.Status.Volumes, volume)
labs = append(labs, lab)
}
return lab, nil
return labs, nil
}

func (p *HetznerProvider) DeleteLab(labName string, force bool) error {
Expand Down
Loading

0 comments on commit 572db27

Please sign in to comment.