Skip to content

Commit 70ced51

Browse files
committed
feat(vm): list start stop
1 parent 7c4363f commit 70ced51

5 files changed

Lines changed: 161 additions & 3 deletions

File tree

cmd/array.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
/*
2-
Copyright © 2025 NAME HERE <EMAIL ADDRESS>
3-
*/
41
package cmd
52

63
import (

cmd/vm.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package cmd
2+
3+
import (
4+
"github.com/spf13/cobra"
5+
"github.com/unshade/unraidctl/internal/controllers"
6+
)
7+
8+
// vmCmd represents the vm command
9+
var vmCmd = &cobra.Command{
10+
Use: "vm",
11+
Short: "Interact with unraid virtual machines",
12+
Long: `Interact with unraid virtual machines. This command allows you to manage your VMs, including starting, stopping, and listing them`,
13+
Run: func(cmd *cobra.Command, args []string) {
14+
controller := controllers.NewVmController(unraidClient)
15+
switch args[0] {
16+
case "list":
17+
controller.ListVMs(cmd.Context())
18+
case "start":
19+
unraidClient.VM.Start(cmd.Context(), args[1])
20+
case "stop":
21+
unraidClient.VM.Stop(cmd.Context(), args[1])
22+
}
23+
},
24+
}
25+
26+
func init() {
27+
rootCmd.AddCommand(vmCmd)
28+
29+
dockerCmd.Args = cobra.MinimumNArgs(1)
30+
dockerCmd.ValidArgs = []string{"force-stop", "pause", "reboot", "reset", "resume", "start", "stop"}
31+
}

internal/controllers/vm.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package controllers
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"strings"
7+
8+
"github.com/unshade/unraidctl/pkg/client"
9+
)
10+
11+
type VmController struct {
12+
unraidClient *client.UnraidClient
13+
}
14+
15+
func NewVmController(unraidClient *client.UnraidClient) *VmController {
16+
return &VmController{
17+
unraidClient: unraidClient,
18+
}
19+
}
20+
21+
func (c *VmController) ListVMs(ctx context.Context) {
22+
respData, err := c.unraidClient.VM.ListVMs(ctx)
23+
if err != nil {
24+
fmt.Printf("Error listing VMs: %v\n", err)
25+
return
26+
}
27+
for _, vm := range respData.VMs.Domains {
28+
idParts := strings.Split(vm.Id, ":")
29+
compactID := idParts[len(idParts)-1]
30+
31+
fmt.Printf("ID: %s | Name: %s | State: %s\n", compactID, vm.Name, vm.State)
32+
}
33+
}

pkg/client/client.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,13 @@ const (
99
type UnraidClient struct {
1010
Docker DockerClient
1111
Array ArrayClient
12+
VM VMClient
1213
}
1314

1415
func NewUnraidClient(apiKey string, graphqlClient *graphql.Client) *UnraidClient {
1516
return &UnraidClient{
1617
Docker: NewDockerClient(apiKey, graphqlClient),
1718
Array: NewArrayClient(apiKey, graphqlClient),
19+
VM: NewVMClient(apiKey, graphqlClient),
1820
}
1921
}

pkg/client/vm.go

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package client
2+
3+
import (
4+
"context"
5+
6+
"github.com/machinebox/graphql"
7+
)
8+
9+
type VMClient interface {
10+
ListVMs(ctx context.Context) (*ListVMsModel, error)
11+
Start(ctx context.Context, id string) (*StartVMModel, error)
12+
Stop(ctx context.Context, id string) (*StopVMModel, error)
13+
}
14+
15+
type RealVMClient struct {
16+
ApiKey string
17+
GraphQLClient *graphql.Client
18+
}
19+
20+
var _ VMClient = (*RealVMClient)(nil)
21+
22+
func NewVMClient(apiKey string, graphqlClient *graphql.Client) VMClient {
23+
return &RealVMClient{
24+
ApiKey: apiKey,
25+
GraphQLClient: graphqlClient,
26+
}
27+
}
28+
29+
type ListVMsModel struct {
30+
VMs struct {
31+
ID string `json:"id"`
32+
Domains []struct {
33+
Name string `json:"name"`
34+
State string `json:"state"`
35+
Id string `json:"id"`
36+
} `json:"domains"`
37+
} `json:"vms"`
38+
}
39+
40+
func (c *RealVMClient) ListVMs(ctx context.Context) (*ListVMsModel, error) {
41+
qglQuery := `
42+
query Query {
43+
vms {
44+
id
45+
domains {
46+
id
47+
name
48+
state
49+
}
50+
}
51+
}`
52+
53+
req := graphql.NewRequest(qglQuery)
54+
auth(req, c.ApiKey)
55+
56+
return query[ListVMsModel](ctx, c.GraphQLClient, req)
57+
}
58+
59+
type StartVMModel struct {
60+
Id string `json:"id"`
61+
}
62+
63+
func (c *RealVMClient) Start(ctx context.Context, id string) (*StartVMModel, error) {
64+
qglQuery := `
65+
mutation Start($startId: PrefixedID!) {
66+
vm {
67+
start(id: $startId)
68+
}
69+
}`
70+
71+
req := graphql.NewRequest(qglQuery)
72+
auth(req, c.ApiKey)
73+
req.Var("startId", id)
74+
75+
return query[StartVMModel](ctx, c.GraphQLClient, req)
76+
}
77+
78+
type StopVMModel struct {
79+
Id string `json:"id"`
80+
}
81+
82+
func (c *RealVMClient) Stop(ctx context.Context, id string) (*StopVMModel, error) {
83+
qglQuery := `
84+
mutation Stop($stopId: PrefixedID!) {
85+
vm {
86+
stop(id: $stopId)
87+
}
88+
}`
89+
90+
req := graphql.NewRequest(qglQuery)
91+
auth(req, c.ApiKey)
92+
req.Var("stopId", id)
93+
94+
return ignoreNotFound(query[StopVMModel](ctx, c.GraphQLClient, req))
95+
}

0 commit comments

Comments
 (0)