~ knotless Search/
↑↓ move↵ open⇧↵ all results
0
0
main
67 lines · 2.9 KB Raw History
package firecracker

import (
	"context"
	"errors"
	"slices"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

	"github.com/johnandersen777/socialweb-computer-kcp/api/v1alpha1"
	"github.com/johnandersen777/socialweb-computer-kcp/internal/contract/compute"

	commonv1 "github.com/johnandersen777/socialweb-computer-kcp/api/common/v1alpha1"
)

var _ compute.Provider = (*Provider)(nil)

func SpecFor(handle string, vm v1alpha1.ComputeVMSpec) v1alpha1.FirecrackerVMSpec {
	return v1alpha1.FirecrackerVMSpec{Owner: v1alpha1.ComputeVMOwner{Handle: handle}, Vcpu: vm.VM.Cpus, Mem: vm.VM.Mem, Disk: vm.VM.Disk,
		Image: vm.Image, UserData: vm.UserData, StopGraceSeconds: vm.StopGraceSeconds, HostPorts: slices.Clone(vm.HostPorts),
		GuestNetwork: v1alpha1.GuestNetworkWith(vm.GuestNetwork.LANUDPAllowed(), vm.GuestNetwork.HostUDPAllowed(), vm.GuestNetwork.WebRTCUDPPortOf())}
}

func (p *Provider) ref(name string) commonv1.ObjectRef {
	return commonv1.ObjectRef{Group: v1alpha1.GroupName, Kind: v1alpha1.BackendKindFirecrackerVM, Name: name}
}

func instanceOf(ref commonv1.ObjectRef, st v1alpha1.FirecrackerVMStatus) compute.Instance {
	in := compute.Instance{Ref: ref, Phase: string(st.Phase), Message: st.Message}
	if n := st.Network; n != nil {
		for _, a := range []string{n.GuestIP, n.HostAddress} {
			if a != "" {
				in.Addresses = append(in.Addresses, a)
			}
		}
	}
	return in
}

func (p *Provider) Provision(ctx context.Context, req compute.ProvisionRequest) (compute.Instance, error) {
	if req.Name == "" {
		return compute.Instance{}, errors.New("firecracker: the provision request names no VM")
	}
	vm := &v1alpha1.FirecrackerVM{ObjectMeta: metav1.ObjectMeta{Name: req.Name},
		Spec: v1alpha1.FirecrackerVMSpec{Owner: v1alpha1.ComputeVMOwner{Handle: p.handle}, Vcpu: req.Shape.CPUs, Mem: req.Shape.Mem,
			Disk: req.Shape.Disk, UserData: v1alpha1.ComputeVMUserData{Vault: req.UserData}}}
	st, err := p.Boot(ctx, vm, func(v1alpha1.FirecrackerVMStatus) error { return nil })
	return instanceOf(p.ref(req.Name), st), err
}

func (p *Provider) Instance(ctx context.Context, ref commonv1.ObjectRef) (compute.Instance, error) {
	rec, err := p.rt.Load(p.handle, ref.Name)
	if err != nil {
		return compute.Instance{Ref: ref, Phase: string(v1alpha1.ComputeVMPhasePending)}, nil
	}
	vm := &v1alpha1.FirecrackerVM{ObjectMeta: metav1.ObjectMeta{Name: ref.Name}, Spec: v1alpha1.FirecrackerVMSpec{Owner: v1alpha1.ComputeVMOwner{Handle: p.handle}},
		Status: runningStatus(v1alpha1.FirecrackerVMStatus{}, 0, rec)}
	return instanceOf(ref, p.Observe(ctx, vm)), nil
}

func (p *Provider) Release(ctx context.Context, ref commonv1.ObjectRef) error {
	vm := &v1alpha1.FirecrackerVM{ObjectMeta: metav1.ObjectMeta{Name: ref.Name}, Spec: v1alpha1.FirecrackerVMSpec{Owner: v1alpha1.ComputeVMOwner{Handle: p.handle}}}
	if rec, err := p.rt.Load(p.handle, ref.Name); err == nil {
		vm.Status = runningStatus(vm.Status, 0, rec)
	}
	return p.Teardown(ctx, vm)
}