Skip to content

Commit

Permalink
Merge pull request #102 from ninech/cloudvm-rescue
Browse files Browse the repository at this point in the history
feat: add rescue boot flags
  • Loading branch information
ctrox authored May 21, 2024
2 parents 4e2ad2c + 26a1d78 commit 542610b
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 27 deletions.
10 changes: 5 additions & 5 deletions create/cloudvm.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@ import (
type cloudVMCmd struct {
Name string `arg:"" default:"" help:"Name of the CloudVM instance. A random name is generated if omitted."`
Location string `default:"nine-es34" help:"Location where the CloudVM instance is created."`
MachineType string `default:"" help:"MachineType defines the sizing for a particular cloud vm."`
MachineType string `default:"" help:"The machine type defines the sizing for a particular CloudVM."`
Hostname string `default:"" help:"Hostname allows to set the hostname explicitly. If unset, the name of the resource will be used as the hostname. This does not affect the DNS name."`
PowerState string `default:"on" help:"PowerState specifies the power state of the cloud VM. A value of On turns the VM on, shutdown sends an ACPI signal to the VM to perform a clean shutdown and off forces the power off immediately."`
PowerState string `default:"on" help:"Specify the initial power state of the CloudVM. Set to off to create "`
OS string `default:"" help:"OS which should be used to boot the VM."`
BootDiskSize string `default:"20Gi" help:"BootDiskSize that will be used to boot the VM from."`
BootDiskSize string `default:"20Gi" help:"Configures the size of the boot disk."`
Disks map[string]string `default:"" help:"Disks specifies which additional disks to mount to the machine."`
PublicKeys []string `default:"" help:"PublicKeys specifies the SSH Public Keys that can be used to connect to the VM as root. The keys are expected to be in SSH format as defined in RFC4253. Immutable after creation."`
PublicKeysFromFiles []string `default:"" predictor:"file" help:"CloudConfig via file. Has precedence over args. PublicKeys specifies the SSH Public Keys that can be used to connect to the VM as root. The keys are expected to be in SSH format as defined in RFC4253. Immutable after creation."`
PublicKeys []string `default:"" help:"SSH public keys that can be used to connect to the CloudVM as root. The keys are expected to be in SSH format as defined in RFC4253. Immutable after creation."`
PublicKeysFromFiles []string `default:"" predictor:"file" help:"SSH public key files that can be used to connect to the VM as root. The keys are expected to be in SSH format as defined in RFC4253. Immutable after creation."`
CloudConfig string `default:"" help:"CloudConfig allows to pass custom cloud config data (https://cloudinit.readthedocs.io/en/latest/topics/format.html#cloud-config-data) to the cloud VM. If a CloudConfig is passed, the PublicKey parameter is ignored. Immutable after creation."`
CloudConfigFromFile string `default:"" predictor:"file" help:"CloudConfig via file. Has precedence over args. CloudConfig allows to pass custom cloud config data (https://cloudinit.readthedocs.io/en/latest/topics/format.html#cloud-config-data) to the cloud VM. If a CloudConfig is passed, the PublicKey parameter is ignored. Immutable after creation."`
Wait bool `default:"true" help:"Wait until CloudVM is created."`
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ require (
github.com/mattn/go-isatty v0.0.20
github.com/moby/moby v26.0.0+incompatible
github.com/moby/term v0.5.0
github.com/ninech/apis v0.0.0-20240514124255-f0f5402eea20
github.com/ninech/apis v0.0.0-20240521070742-7162e783d4de
github.com/posener/complete v1.2.3
github.com/prometheus/common v0.52.2
github.com/stretchr/testify v1.9.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,8 @@ github.com/ninech/apis v0.0.0-20240506094307-4fe0aeaf591e h1:RKYSj5TeIkOiofU6RSj
github.com/ninech/apis v0.0.0-20240506094307-4fe0aeaf591e/go.mod h1:6lFCwHqvcTFZvJ6zY0rxaPIoKc0CX9sHhtH/nyo/5is=
github.com/ninech/apis v0.0.0-20240514124255-f0f5402eea20 h1:QMIxpbxHDjyAXn24K1j3DHfiH8sbDoM2WIb+YNZhGQg=
github.com/ninech/apis v0.0.0-20240514124255-f0f5402eea20/go.mod h1:6lFCwHqvcTFZvJ6zY0rxaPIoKc0CX9sHhtH/nyo/5is=
github.com/ninech/apis v0.0.0-20240521070742-7162e783d4de h1:UWX/X1Gc0AAx9vr1GOMb9ZBLsB43DooI+SyZMcFHAkE=
github.com/ninech/apis v0.0.0-20240521070742-7162e783d4de/go.mod h1:6lFCwHqvcTFZvJ6zY0rxaPIoKc0CX9sHhtH/nyo/5is=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
Expand Down
73 changes: 52 additions & 21 deletions update/cloudvm.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package update
import (
"context"
"fmt"
"os"

"github.com/crossplane/crossplane-runtime/pkg/resource"
infrastructure "github.com/ninech/apis/infrastructure/v1alpha1"
Expand All @@ -13,15 +14,18 @@ import (
)

type cloudVMCmd struct {
Name string `arg:"" help:"Name of the CloudVM instance to update."`
MachineType string `placeholder:"nine-standard-1" help:"MachineType defines the sizing for a particular cloud vm."`
Hostname string `placeholder:"" help:"Hostname allows to set the hostname explicitly. If unset, the name of the resource will be used as the hostname. This does not affect the DNS name."`
OS string `placeholder:"ubuntu22.04" help:"OS which should be used to boot the VM."`
BootDisk map[string]string `placeholder:"{name:\"root\",size:\"20Gi\"}" help:"BootDisk that will be used to boot the VM from. Needs to be in the following format: {name:\"<name>\",size:\"<size>Gi\"}"`
Disks map[string]string `placeholder:"{}" help:"Disks specifies which additional disks to mount to the machine."`
On *bool `placeholder:"false" help:"Turns the cloudvirtualmachine on"`
Off *bool `placeholder:"false" help:"Turns the cloudvirtualmachine off"`
Shutdown *bool `placeholder:"false" help:"Shuts off the cloudvirtualmachine"`
Name string `arg:"" help:"Name of the CloudVM instance to update."`
MachineType string `placeholder:"nine-standard-1" help:"The machine type defines the sizing for a particular CloudVM."`
Hostname string `placeholder:"" help:"Hostname allows to set the hostname explicitly. If unset, the name of the resource will be used as the hostname. This does not affect the DNS name."`
OS string `placeholder:"ubuntu22.04" help:"OS which should be used to boot the VM."`
BootDiskSize string `placeholder:"20Gi" help:"Configures the size of the boot disk."`
Disks map[string]string `placeholder:"{}" help:"Disks specifies which additional disks to mount to the machine."`
On *bool `help:"Turns the CloudVM on."`
Off *bool `help:"Turns the CloudVM off immediately."`
Shutdown *bool `help:"Shuts down the CloudVM via ACPI."`
BootRescue *bool `help:"Boot CloudVM into a live rescue environment."`
RescuePublicKeys []string `placeholder:"ssh-ed25519" help:"SSH public keys that can be used to connect to the CloudVM while booted into rescue. The keys are expected to be in SSH format as defined in RFC4253."`
RescuePublicKeysFromFiles []string `placeholder:"~/.ssh/id_ed25519.pub" predictor:"file" help:"SSH public key files that can be used to connect to the CloudVM while booted into rescue. The keys are expected to be in SSH format as defined in RFC4253."`
}

func (cmd *cloudVMCmd) Run(ctx context.Context, client *api.Client) error {
Expand All @@ -32,14 +36,22 @@ func (cmd *cloudVMCmd) Run(ctx context.Context, client *api.Client) error {
},
}

return newUpdater(client, cloudvm, infrastructure.CloudVirtualMachineKind, func(current resource.Managed) error {
if err := newUpdater(client, cloudvm, infrastructure.CloudVirtualMachineKind, func(current resource.Managed) error {
cloudvm, ok := current.(*infrastructure.CloudVirtualMachine)
if !ok {
return fmt.Errorf("resource is of type %T, expected %T", current, infrastructure.CloudVirtualMachine{})
}

return cmd.applyUpdates(cloudvm)
}).Update(ctx)
}).Update(ctx); err != nil {
return err
}

if cmd.BootRescue != nil && *cmd.BootRescue {
fmt.Println("Booting CloudVM into rescue mode. It can take a few minutes for the VM to be reachable.")
}

return nil
}

func (cmd *cloudVMCmd) applyUpdates(cloudVM *infrastructure.CloudVirtualMachine) error {
Expand All @@ -55,17 +67,12 @@ func (cmd *cloudVMCmd) applyUpdates(cloudVM *infrastructure.CloudVirtualMachine)
cloudVM.Spec.ForProvider.OS = infrastructure.CloudVirtualMachineOS(cmd.OS)
}

if len(cmd.BootDisk) != 0 {
if len(cmd.BootDisk) > 1 {
return fmt.Errorf("boot disk can only have one entry but got %q", cmd.BootDisk)
}
for name, size := range cmd.BootDisk {
q, err := res.ParseQuantity(size)
if err != nil {
return fmt.Errorf("error parsing disk size %q: %w", size, err)
}
cloudVM.Spec.ForProvider.BootDisk = &infrastructure.Disk{Name: name, Size: q}
if cmd.BootDiskSize != "" {
q, err := res.ParseQuantity(cmd.BootDiskSize)
if err != nil {
return fmt.Errorf("error parsing disk size %q: %w", cmd.BootDiskSize, err)
}
cloudVM.Spec.ForProvider.BootDisk = &infrastructure.Disk{Name: cmd.BootDiskSize, Size: q}
}

if len(cmd.Disks) != 0 {
Expand All @@ -92,5 +99,29 @@ func (cmd *cloudVMCmd) applyUpdates(cloudVM *infrastructure.CloudVirtualMachine)
cloudVM.Spec.ForProvider.PowerState = infrastructure.VirtualMachinePowerState("on")
}

if cmd.BootRescue != nil {
if cloudVM.Spec.ForProvider.Rescue == nil {
cloudVM.Spec.ForProvider.Rescue = &infrastructure.CloudVirtualMachineRescue{Enabled: *cmd.BootRescue}
} else {
cloudVM.Spec.ForProvider.Rescue.Enabled = *cmd.BootRescue
}
}

if len(cmd.RescuePublicKeysFromFiles) != 0 {
var keys []string
for _, file := range cmd.RescuePublicKeysFromFiles {
b, err := os.ReadFile(file)
if err != nil {
return fmt.Errorf("error reading public key file %q: %w", cmd.RescuePublicKeysFromFiles, err)
}
keys = append(keys, string(b))
}
if cloudVM.Spec.ForProvider.Rescue == nil {
cloudVM.Spec.ForProvider.Rescue = &infrastructure.CloudVirtualMachineRescue{PublicKeys: keys}
} else {
cloudVM.Spec.ForProvider.Rescue.PublicKeys = keys
}
}

return nil
}

0 comments on commit 542610b

Please sign in to comment.