256 lines
5.6 KiB
Go
256 lines
5.6 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
|
|
"esxlib/api/cloud"
|
|
"esxlib/pkg/pprint"
|
|
|
|
"github.com/urfave/cli/v2"
|
|
)
|
|
|
|
var (
|
|
vmIdFlag = cli.StringFlag{
|
|
Name: "vm.id",
|
|
Value: "",
|
|
Usage: "The id of the vm to fetch",
|
|
}
|
|
|
|
vmNameFlag = cli.StringFlag{
|
|
Name: "vm.name",
|
|
Value: "",
|
|
Required: true,
|
|
Usage: "The id of the vm to fetch",
|
|
}
|
|
|
|
slugIdFlag = cli.StringFlag{
|
|
Name: "slug.id",
|
|
Value: "",
|
|
Required: true,
|
|
Usage: "The id of the slug to use",
|
|
}
|
|
|
|
sshKeyFileFlag = cli.StringFlag{
|
|
Name: "ssh.hosts",
|
|
Value: "",
|
|
Usage: "SSH authorized host file to load keys from",
|
|
}
|
|
|
|
cloudInitFileFlag = cli.StringFlag{
|
|
Name: "cloudinit.file",
|
|
Value: "",
|
|
Usage: "CloudInit file to load",
|
|
}
|
|
)
|
|
|
|
var vmCommands = []*cli.Command{
|
|
{
|
|
Name: "list",
|
|
Aliases: []string{"ls", "list"},
|
|
Usage: "list virtual machines",
|
|
Description: "list virtual machines",
|
|
Flags: []cli.Flag{},
|
|
Action: vmCommandList,
|
|
},
|
|
{
|
|
Name: "get",
|
|
Aliases: []string{"get"},
|
|
Usage: "get details of a virtual machine",
|
|
Description: "get details of a virtual machines",
|
|
Flags: []cli.Flag{
|
|
&vmIdFlag,
|
|
},
|
|
Action: vmCommandGet,
|
|
},
|
|
|
|
{
|
|
Name: "power-on",
|
|
Aliases: []string{"poweron", "on", "resume"},
|
|
Usage: "Power on/resume a Virtual machine",
|
|
Description: "Power on/resume a Virtual machine",
|
|
Flags: []cli.Flag{
|
|
&vmIdFlag,
|
|
},
|
|
Action: vmCommandPowerOn,
|
|
},
|
|
{
|
|
Name: "power-off",
|
|
Aliases: []string{"poweroff", "off"},
|
|
Usage: "Power off a Virtual machine",
|
|
Description: "Power off a Virtual machine",
|
|
Flags: []cli.Flag{
|
|
&vmIdFlag,
|
|
},
|
|
Action: vmCommandPowerOff,
|
|
},
|
|
{
|
|
Name: "suspend",
|
|
Aliases: []string{"suspend"},
|
|
Usage: "Suspend a Virtual machine",
|
|
Description: "Suspend a Virtual machine",
|
|
Flags: []cli.Flag{
|
|
&vmIdFlag,
|
|
},
|
|
Action: vmCommandPowerSuspend,
|
|
},
|
|
{
|
|
Name: "destroy",
|
|
Aliases: []string{"destroy"},
|
|
Usage: "Destroy an existing virtual machine",
|
|
Description: "Destroy an existing virtual machine",
|
|
Flags: []cli.Flag{
|
|
&vmIdFlag,
|
|
},
|
|
Action: vmCommandDestroy,
|
|
},
|
|
|
|
{
|
|
Name: "create",
|
|
Aliases: []string{"create"},
|
|
Usage: "Create a new virtual machine",
|
|
Description: "Create a new virtual machine",
|
|
Flags: []cli.Flag{
|
|
&vmNameFlag,
|
|
&zoneIdFlag,
|
|
&slugIdFlag,
|
|
&sshKeyFileFlag,
|
|
&cloudInitFileFlag,
|
|
},
|
|
Action: vmCommandCreate,
|
|
},
|
|
}
|
|
|
|
func vmCommandList(ctx *cli.Context) error {
|
|
client := mustGetClient(ctx)
|
|
|
|
resp, err := client.VMList(context.Background(), &cloud.VMListRequest{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
out := pprint.NewPrinter("human", os.Stdout)
|
|
|
|
out.Headers("VMID", "Name", "State", "Address")
|
|
for _, vm := range resp.Vms {
|
|
address := ""
|
|
// just grab the last one (we can do better later
|
|
for _, a := range vm.Network {
|
|
address = a.Address
|
|
}
|
|
out.Fields(vm.Id, vm.Name, vm.State, address)
|
|
}
|
|
out.Flush()
|
|
return nil
|
|
}
|
|
|
|
func vmCommandGet(ctx *cli.Context) error {
|
|
client := mustGetClient(ctx)
|
|
|
|
resp, err := client.VMGet(context.Background(), &cloud.VMGetRequest{
|
|
Search: &cloud.VMGetRequest_Id{
|
|
Id: ctx.String(vmIdFlag.Name),
|
|
},
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
out := pprint.NewPrinter("human", os.Stdout)
|
|
vm := resp.Vm
|
|
out.Headers("VMID", "Name", "State", "Address")
|
|
address := ""
|
|
// just grab the last one (we can do better later
|
|
for _, a := range vm.Network {
|
|
address = a.Address
|
|
}
|
|
out.Fields(vm.Id, vm.Name, vm.State, address)
|
|
out.Flush()
|
|
return nil
|
|
}
|
|
|
|
func vmCommandPower(ctx *cli.Context, newState cloud.PowerState) error {
|
|
client := mustGetClient(ctx)
|
|
|
|
_, err := client.VMPower(context.Background(), &cloud.VMPowerRequest{
|
|
Id: ctx.String(vmIdFlag.Name),
|
|
State: newState,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func vmCommandPowerOn(ctx *cli.Context) error {
|
|
return vmCommandPower(ctx, cloud.PowerState_ON)
|
|
}
|
|
|
|
func vmCommandPowerOff(ctx *cli.Context) error {
|
|
return vmCommandPower(ctx, cloud.PowerState_OFF)
|
|
}
|
|
|
|
func vmCommandPowerSuspend(ctx *cli.Context) error {
|
|
return vmCommandPower(ctx, cloud.PowerState_SUSPENDED)
|
|
}
|
|
|
|
func vmCommandCreate(ctx *cli.Context) error {
|
|
client := mustGetClient(ctx)
|
|
|
|
sshAuthorizedHosts := ""
|
|
if ctx.String(sshKeyFileFlag.Name) != "" {
|
|
data, err := os.ReadFile(ctx.String(sshKeyFileFlag.Name))
|
|
if err != nil {
|
|
return fmt.Errorf("Could not read hosts file: %s\n", ctx.String(sshKeyFileFlag.Name))
|
|
}
|
|
sshAuthorizedHosts = string(data)
|
|
}
|
|
|
|
cloudInit := ""
|
|
if ctx.String(cloudInitFileFlag.Name) != "" {
|
|
data, err := os.ReadFile(ctx.String(cloudInitFileFlag.Name))
|
|
if err != nil {
|
|
return fmt.Errorf("Could not read cloud init file: %s\n", ctx.String(cloudInitFileFlag.Name))
|
|
}
|
|
cloudInit = string(data)
|
|
}
|
|
|
|
req := cloud.VMCreateRequest{
|
|
Name: ctx.String(vmNameFlag.Name),
|
|
ZoneId: ctx.String(zoneIdFlag.Name),
|
|
Slug: ctx.String(slugIdFlag.Name),
|
|
InitScript: cloudInit,
|
|
AuthorizedHosts: []string{sshAuthorizedHosts},
|
|
}
|
|
|
|
resp, err := client.VMCreate(context.Background(), &req)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
out := pprint.NewPrinter("human", os.Stdout)
|
|
vm := resp.Vm
|
|
out.Headers("VMID", "Name", "State", "Address")
|
|
address := ""
|
|
// just grab the last one (we can do better later
|
|
for _, a := range vm.Network {
|
|
address = a.Address
|
|
}
|
|
out.Fields(vm.Id, vm.Name, vm.State, address)
|
|
out.Flush()
|
|
return nil
|
|
}
|
|
|
|
func vmCommandDestroy(ctx *cli.Context) error {
|
|
client := mustGetClient(ctx)
|
|
_, err := client.VMDestroy(context.Background(), &cloud.VMDestroyRequest{
|
|
Id: ctx.String(vmIdFlag.Name),
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|