Skip to content

Commit

Permalink
feat: add UI controls for VM inject partition and disk persistence
Browse files Browse the repository at this point in the history
Makes the following changes:
* Adds column in StoppedExperiments for setting inject partition
* Adds column in StoppedExperiments for toggling persistence (snapshot) on and off
* Fixes issue with disk dropdowns not populating
* Removes date in known_policy.go generation so file isn't updated every build
* Minor tweaks to column with in StoppedExperiments table

Note: I did not directly write all of these changes, but have pulled them up from an internal repo.
  • Loading branch information
Justin Mott authored and activeshadow committed Sep 30, 2024
1 parent 9024224 commit ca1a374
Show file tree
Hide file tree
Showing 14 changed files with 333 additions and 123 deletions.
30 changes: 22 additions & 8 deletions src/go/api/vm/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,16 @@ type iface struct {
}

type updateOptions struct {
exp string
vm string
cpu int
mem int
disk string
dnb *bool
iface *iface
host *string
exp string
vm string
cpu int
mem int
disk string
partition int
dnb *bool
iface *iface
host *string
snapshot *bool
}

func newUpdateOptions(opts ...UpdateOption) updateOptions {
Expand Down Expand Up @@ -58,6 +60,12 @@ func UpdateWithDisk(d string) UpdateOption {
}
}

func UpdateWithPartition(p int) UpdateOption {
return func(o *updateOptions) {
o.partition = p
}
}

func UpdateWithInterface(i int, v string) UpdateOption {
return func(o *updateOptions) {
o.iface = &iface{index: i, vlan: v}
Expand All @@ -70,6 +78,12 @@ func UpdateWithDNB(b bool) UpdateOption {
}
}

func UpdateWithSnapshot(b bool) UpdateOption {
return func(o *updateOptions) {
o.snapshot = &b
}
}

func UpdateWithHost(h string) UpdateOption {
return func(o *updateOptions) {
o.host = &h
Expand Down
68 changes: 43 additions & 25 deletions src/go/api/vm/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,29 +65,37 @@ func List(expName string) ([]mm.VM, error) {

for idx, node := range exp.Spec.Topology().Nodes() {
var (
disk string
dnb bool
disk string
dnb bool
snapshot bool
injectPartition int
)

if drives := node.Hardware().Drives(); len(drives) > 0 {
disk = drives[0].Image()
disk = util.GetMMFullPath(drives[0].Image())
injectPartition = *drives[0].InjectPartition()
}

if node.General().DoNotBoot() != nil {
dnb = *node.General().DoNotBoot()
}
if node.General().Snapshot() != nil {
snapshot = *node.General().Snapshot()
}

vm := mm.VM{
ID: idx,
Name: node.General().Hostname(),
Experiment: exp.Spec.ExperimentName(),
CPUs: node.Hardware().VCPU(),
RAM: node.Hardware().Memory(),
Disk: disk,
Interfaces: make(map[string]string),
DoNotBoot: dnb,
Type: node.Type(),
OSType: node.Hardware().OSType(),
ID: idx,
Name: node.General().Hostname(),
Experiment: exp.Spec.ExperimentName(),
CPUs: node.Hardware().VCPU(),
RAM: node.Hardware().Memory(),
Disk: disk,
InjectPartition: injectPartition,
Interfaces: make(map[string]string),
DoNotBoot: dnb,
Type: node.Type(),
OSType: node.Hardware().OSType(),
Snapshot: snapshot,
}

for _, iface := range node.Network().Interfaces() {
Expand Down Expand Up @@ -179,18 +187,20 @@ func Get(expName, vmName string) (*mm.VM, error) {
}

vm = &mm.VM{
ID: idx,
Name: node.General().Hostname(),
Experiment: exp.Spec.ExperimentName(),
CPUs: node.Hardware().VCPU(),
RAM: node.Hardware().Memory(),
Disk: util.GetMMFullPath(node.Hardware().Drives()[0].Image()),
Interfaces: make(map[string]string),
DoNotBoot: *node.General().DoNotBoot(),
OSType: string(node.Hardware().OSType()),
Metadata: make(map[string]interface{}),
Labels: node.Labels(),
Annotations: node.Annotations(),
ID: idx,
Name: node.General().Hostname(),
Experiment: exp.Spec.ExperimentName(),
CPUs: node.Hardware().VCPU(),
RAM: node.Hardware().Memory(),
Disk: util.GetMMFullPath(node.Hardware().Drives()[0].Image()),
InjectPartition: *node.Hardware().Drives()[0].InjectPartition(),
Interfaces: make(map[string]string),
DoNotBoot: *node.General().DoNotBoot(),
OSType: string(node.Hardware().OSType()),
Metadata: make(map[string]interface{}),
Labels: node.Labels(),
Annotations: node.Annotations(),
Snapshot: *node.General().Snapshot(),
}

for _, iface := range node.Network().Interfaces() {
Expand Down Expand Up @@ -312,6 +322,10 @@ func Update(opts ...UpdateOption) error {
vm.Hardware().Drives()[0].SetImage(o.disk)
}

if o.partition != 0 {
vm.Hardware().Drives()[0].SetInjectPartition(&o.partition)
}

if o.dnb != nil {
vm.General().SetDoNotBoot(*o.dnb)
}
Expand All @@ -324,6 +338,10 @@ func Update(opts ...UpdateOption) error {
}
}

if o.snapshot != nil {
vm.General().SetSnapshot(*o.snapshot)
}

err = experiment.Save(experiment.SaveWithName(o.exp), experiment.SaveWithSpec(exp.Spec))
if err != nil {
return fmt.Errorf("unable to save experiment with updated VM: %w", err)
Expand Down
2 changes: 1 addition & 1 deletion src/go/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ require (
golang.org/x/crypto v0.1.0
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1
golang.org/x/net v0.1.0
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4
golang.org/x/term v0.1.0
google.golang.org/protobuf v1.25.0
gopkg.in/yaml.v2 v2.4.0
Expand Down
4 changes: 2 additions & 2 deletions src/go/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -447,8 +447,8 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
Expand Down
2 changes: 2 additions & 0 deletions src/go/types/interfaces/topology.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ type NodeGeneral interface {
Description() string
VMType() string
Snapshot() *bool
SetSnapshot(bool)
DoNotBoot() *bool

SetDoNotBoot(bool)
Expand All @@ -80,6 +81,7 @@ type NodeDrive interface {
CacheMode() string
InjectPartition() *int

SetInjectPartition(*int)
SetImage(string)
}

Expand Down
9 changes: 9 additions & 0 deletions src/go/types/version/v0/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ type Node struct {
HardwareF *Hardware `json:"hardware" yaml:"hardware" structs:"hardware" mapstructure:"hardware"`
NetworkF *Network `json:"network" yaml:"network" structs:"network" mapstructure:"network"`
InjectionsF []*Injection `json:"injections" yaml:"injections" structs:"injections" mapstructure:"injections"`

}

func (this Node) Annotations() map[string]interface{} {
Expand Down Expand Up @@ -168,6 +169,7 @@ type General struct {
VMTypeF string `json:"vm_type" yaml:"vm_type" structs:"vm_type" mapstructure:"vm_type"`
SnapshotF *bool `json:"snapshot" yaml:"snapshot" structs:"snapshot" mapstructure:"snapshot"`
DoNotBootF *bool `json:"do_not_boot" yaml:"do_not_boot" structs:"do_not_boot" mapstructure:"do_not_boot"`

}

func (this General) Hostname() string {
Expand All @@ -185,6 +187,9 @@ func (this General) VMType() string {
func (this General) Snapshot() *bool {
return this.SnapshotF
}
func (this *General) SetSnapshot(b bool) {
this.SnapshotF = &b
}

func (this General) DoNotBoot() *bool {
return this.DoNotBootF
Expand Down Expand Up @@ -279,6 +284,10 @@ func (this *Drive) SetImage(i string) {
this.ImageF = i
}

func (this *Drive) SetInjectPartition(p *int) {
this.InjectPartitionF = p
}

type Injection struct {
SrcF string `json:"src" yaml:"src" structs:"src" mapstructure:"src"`
DstF string `json:"dst" yaml:"dst" structs:"dst" mapstructure:"dst"`
Expand Down
8 changes: 8 additions & 0 deletions src/go/types/version/v1/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,10 @@ func (this *General) Snapshot() *bool {
return this.SnapshotF
}

func (this *General) SetSnapshot(b bool) {
this.SnapshotF = &b
}

func (this *General) DoNotBoot() *bool {
if this == nil {
return nil
Expand Down Expand Up @@ -418,6 +422,10 @@ func (this *Drive) SetImage(i string) {
this.ImageF = i
}

func (this *Drive) SetInjectPartition(p *int) {
this.InjectPartitionF = p
}

type Injection struct {
SrcF string `json:"src" yaml:"src" structs:"src" mapstructure:"src"`
DstF string `json:"dst" yaml:"dst" structs:"dst" mapstructure:"dst"`
Expand Down
46 changes: 24 additions & 22 deletions src/go/util/mm/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,28 +206,30 @@ func (this VMs) Paginate(page, size int) VMs {
}

type VM struct {
ID int `json:"id"`
Name string `json:"name"`
Type string `json:"type"`
Experiment string `json:"experiment"`
Host string `json:"host"`
IPv4 []string `json:"ipv4"`
CPUs int `json:"cpus"`
RAM int `json:"ram"`
Disk string `json:"disk"`
OSType string `json:"osType"`
DoNotBoot bool `json:"dnb"`
Networks []string `json:"networks"`
Taps []string `json:"taps"`
Captures []Capture `json:"captures"`
State string `json:"state"`
Running bool `json:"running"`
Busy bool `json:"busy"`
CCActive bool `json:"ccActive"`
Uptime float64 `json:"uptime"`
Screenshot string `json:"screenshot,omitempty"`
CdRom string `json:"cdRom"`
Tags []string `json:"tags"`
ID int `json:"id"`
Name string `json:"name"`
Type string `json:"type"`
Experiment string `json:"experiment"`
Host string `json:"host"`
IPv4 []string `json:"ipv4"`
CPUs int `json:"cpus"`
RAM int `json:"ram"`
Disk string `json:"disk"`
InjectPartition int `json:"inject_partition`
OSType string `json:"osType"`
DoNotBoot bool `json:"dnb"`
Networks []string `json:"networks"`
Taps []string `json:"taps"`
Captures []Capture `json:"captures"`
State string `json:"state"`
Running bool `json:"running"`
Busy bool `json:"busy"`
CCActive bool `json:"ccActive"`
Uptime float64 `json:"uptime"`
Screenshot string `json:"screenshot,omitempty"`
CdRom string `json:"cdRom"`
Tags []string `json:"tags"`
Snapshot bool `json:"snapshot"`

// Used internally to track network <--> IP relationship, since
// network ordering from minimega may not be the same as network
Expand Down
11 changes: 11 additions & 0 deletions src/go/web/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -1038,6 +1038,7 @@ func UpdateVM(w http.ResponseWriter, r *http.Request) {
vm.UpdateWithCPU(int(req.Cpus)),
vm.UpdateWithMem(int(req.Ram)),
vm.UpdateWithDisk(req.Disk),
vm.UpdateWithPartition(int(req.InjectPartition)),
}

if req.Interface != nil {
Expand All @@ -1053,6 +1054,11 @@ func UpdateVM(w http.ResponseWriter, r *http.Request) {
case *proto.UpdateVMRequest_Host:
opts = append(opts, vm.UpdateWithHost(req.GetHost()))
}

switch req.SnapshotOption.(type) {
case *proto.UpdateVMRequest_Snapshot:
opts = append(opts, vm.UpdateWithSnapshot(req.GetSnapshot()))
}

if err := vm.Update(opts...); err != nil {
plog.Error("updating VM", "err", err)
Expand Down Expand Up @@ -1151,6 +1157,11 @@ func UpdateVMs(w http.ResponseWriter, r *http.Request) {
opts = append(opts, vm.UpdateWithHost(vmRequest.GetHost()))
}

switch vmRequest.SnapshotOption.(type) {
case *proto.UpdateVMRequest_Snapshot:
opts = append(opts, vm.UpdateWithSnapshot(vmRequest.GetSnapshot()))
}

if err := vm.Update(opts...); err != nil {
plog.Error("updating VM", "err", err)
http.Error(w, "unable to update VM", http.StatusInternalServerError)
Expand Down
9 changes: 8 additions & 1 deletion src/go/web/proto/vm.proto
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ message VM {
repeated string tags = 18;
bool cc_active = 19;
bool external = 20;

string delayed_start = 21 [json_name="delayed_start"];
bool snapshot = 22 [json_name="snapshot"];
uint32 inject_partition = 23 [json_name="inject_partition"];
}

message VMList {
Expand Down Expand Up @@ -70,6 +71,12 @@ message UpdateVMRequest {
oneof cluster_host {
string host = 8;
}

oneof snapshot_option {
bool snapshot = 9 [json_name="snapshot"];
}

uint32 inject_partition = 10 [json_name="inject_partition"];
}

message UpdateVMRequestList {
Expand Down
4 changes: 2 additions & 2 deletions src/go/web/rbac/known_policy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit ca1a374

Please sign in to comment.