Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Various Fixes for Actions Taken on VMs #194

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions src/go/api/cluster/files.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"strings"

"phenix/api/experiment"
"phenix/util"
"phenix/util/mm"
"phenix/util/mm/mmcli"
)
Expand All @@ -30,7 +29,7 @@ type ImageDetails struct {
}

var DefaultClusterFiles ClusterFiles = new(MMClusterFiles)
var mmFilesDirectory = util.GetMMFilesDirectory()
var mmFilesDirectory = mm.GetMMFilesDirectory()

type ClusterFiles interface {
// Get list of VM disk images, container filesystems, or both.
Expand Down Expand Up @@ -298,7 +297,7 @@ func getAllFiles(details map[string]ImageDetails) error {

image := ImageDetails{
Name: baseName,
FullPath: util.GetMMFullPath(row["name"]),
FullPath: mm.GetMMFullPath(row["name"]),
}

if strings.HasSuffix(image.Name, ".qc2") || strings.HasSuffix(image.Name, ".qcow2") {
Expand Down Expand Up @@ -367,7 +366,7 @@ func getTopologyFiles(expName string, details map[string]ImageDetails) error {

image := ImageDetails{
Name: baseName,
FullPath: util.GetMMFullPath(row["name"]),
FullPath: mm.GetMMFullPath(row["name"]),
Kind: VM_IMAGE,
}

Expand Down
28 changes: 16 additions & 12 deletions src/go/api/vm/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ import (
"time"

"phenix/api/experiment"
"phenix/util"
"phenix/util/common"
"phenix/util/file"
"phenix/util/mm"
"phenix/util/mm/mmcli"
"phenix/util/plog"

"golang.org/x/sync/errgroup"
)
Expand Down Expand Up @@ -184,7 +184,7 @@ func Get(expName, vmName string) (*mm.VM, error) {
Experiment: exp.Spec.ExperimentName(),
CPUs: node.Hardware().VCPU(),
RAM: node.Hardware().Memory(),
Disk: util.GetMMFullPath(node.Hardware().Drives()[0].Image()),
Disk: mm.GetMMFullPath(node.Hardware().Drives()[0].Image()),
Interfaces: make(map[string]string),
DoNotBoot: *node.General().DoNotBoot(),
OSType: string(node.Hardware().OSType()),
Expand Down Expand Up @@ -874,53 +874,57 @@ func Restore(expName, vmName, snap string) error {

snap = fmt.Sprintf("%s/files/%s", expName, snap)

details := mm.GetVMInfo(mm.NS(expName), mm.VMName(vmName))
if len(details) == 0 {
return fmt.Errorf("error getting vm details")
}

cmd := mmcli.NewNamespacedCommand(expName)
cmd.Command = fmt.Sprintf("vm config clone %s", vmName)

if err := mmcli.ErrorResponse(mmcli.Run(cmd)); err != nil {
return fmt.Errorf("cloning config for VM %s: %w", vmName, err)
}

cmd.Command = fmt.Sprintf("vm config migrate %s.SNAP", snap)
// Have to copy over UUID separate from clone.
// Needs to stay the same for miniccc agent to connect
plog.Info("Setting UUID", "uuid", details[0].UUID)
cmd.Command = fmt.Sprintf("vm config uuid %s", details[0].UUID)
if err := mmcli.ErrorResponse(mmcli.Run(cmd)); err != nil {
return fmt.Errorf("setting uuid for VM %s: %w", vmName, err)
}

cmd.Command = fmt.Sprintf("vm config migrate %s.SNAP", snap)
if err := mmcli.ErrorResponse(mmcli.Run(cmd)); err != nil {
return fmt.Errorf("configuring migrate file for VM %s: %w", vmName, err)
}

cmd.Command = fmt.Sprintf("vm config disk %s.qc2,writeback", snap)

if err := mmcli.ErrorResponse(mmcli.Run(cmd)); err != nil {
return fmt.Errorf("configuring disk file for VM %s: %w", vmName, err)
}

cmd.Command = fmt.Sprintf("vm kill %s", vmName)

if err := mmcli.ErrorResponse(mmcli.Run(cmd)); err != nil {
return fmt.Errorf("killing VM %s: %w", vmName, err)
}

// TODO: explicitly flush killed VM by name once we start using that version
// of minimega.
cmd.Command = "vm flush"

cmd.Command = fmt.Sprintf("vm flush %s", vmName)
if err := mmcli.ErrorResponse(mmcli.Run(cmd)); err != nil {
return fmt.Errorf("flushing VMs: %w", err)
}

cmd.Command = fmt.Sprintf("vm launch kvm %s", vmName)

if err := mmcli.ErrorResponse(mmcli.Run(cmd)); err != nil {
return fmt.Errorf("relaunching VM %s: %w", vmName, err)
}

cmd.Command = "vm launch"

if err := mmcli.ErrorResponse(mmcli.Run(cmd)); err != nil {
return fmt.Errorf("scheduling VM %s: %w", vmName, err)
}

cmd.Command = fmt.Sprintf("vm start %s", vmName)

if err := mmcli.ErrorResponse(mmcli.Run(cmd)); err != nil {
return fmt.Errorf("starting VM %s: %w", vmName, err)
}
Expand Down
80 changes: 0 additions & 80 deletions src/go/util/file.go

This file was deleted.

45 changes: 45 additions & 0 deletions src/go/util/mm/file.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package mm

import (
"fmt"
"path/filepath"
"strings"

"phenix/util/common"
"phenix/util/plog"
)

var (
mmFilesDirectory = GetMMFilesDirectory()
)

// Returns the full path relative to the minimega files directory
func GetMMFullPath(path string) string {
// If there is no leading file separator, assume a relative
// path to the minimega files directory
if !strings.HasPrefix(path, "/") {
return filepath.Join(mmFilesDirectory, path)
} else {
return path
}

}

// Tries to extract the minimega files directory from a process listing
func GetMMFilesDirectory() string {
defaultMMFilesDirectory := fmt.Sprintf("%s/images", common.PhenixBase)

args, err := GetMMArgs()
if err != nil {
plog.Warn("Could not get mm files directory from minimega")
return defaultMMFilesDirectory
}

path, ok := args["filepath"]
if !ok {
plog.Warn("Could not get mm files directory from minimega")
return defaultMMFilesDirectory
}

return path
}
10 changes: 10 additions & 0 deletions src/go/util/mm/minimega.go
Original file line number Diff line number Diff line change
Expand Up @@ -816,6 +816,16 @@ func (this Minimega) IsHeadnode(node string) bool {
return node == this.Headnode()
}

func (this Minimega) GetMMArgs() (map[string]string, error) {
cmd := mmcli.NewCommand()
cmd.Command = "args"
rows := mmcli.RunTabular(cmd)
if len(rows) == 1 {
return rows[0], nil
}
return nil, fmt.Errorf("no args returned")
}

func (Minimega) GetVLANs(opts ...Option) (map[string]int, error) {
o := NewOptions(opts...)

Expand Down
1 change: 1 addition & 0 deletions src/go/util/mm/mm.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ type MM interface {
GetNamespaceHosts(string) (Hosts, error)
Headnode() string
IsHeadnode(string) bool
GetMMArgs() (map[string]string, error)
GetVLANs(...Option) (map[string]int, error)

IsC2ClientActive(...C2Option) error
Expand Down
4 changes: 4 additions & 0 deletions src/go/util/mm/package.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,10 @@ func IsHeadnode(node string) bool {
return DefaultMM.IsHeadnode(node)
}

func GetMMArgs() (map[string]string, error) {
return DefaultMM.GetMMArgs()
}

func GetVLANs(opts ...Option) (map[string]int, error) {
return DefaultMM.GetVLANs(opts...)
}
Expand Down
4 changes: 3 additions & 1 deletion src/go/web/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -2438,10 +2438,12 @@ func CreateVMMemorySnapshot(w http.ResponseWriter, r *http.Request) {
return
}

marshalled, _ := json.Marshal(util.WithRoot("disk", filename))

broker.Broadcast(
bt.NewRequestPolicy("vms/memorySnapshot", "create", fmt.Sprintf("%s/%s", exp, name)),
bt.NewResource("experiment/vm/memorySnapshot", exp+"/"+name, "commit"),
nil,
marshalled,
)

w.WriteHeader(http.StatusNoContent)
Expand Down
19 changes: 8 additions & 11 deletions src/go/web/mount.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import (
"phenix/util/mm"
"phenix/util/plog"
"phenix/web/rbac"
"phenix/web/util"

"github.com/gorilla/mux"
)
Expand Down Expand Up @@ -121,6 +120,7 @@ func UnmountVM(w http.ResponseWriter, r *http.Request) {
}

// GET /experiments/{exp}/vms/{name}/mount/files?path=
// Note: error may be returned inside json body as Readdir can return an error with entries
func GetMountFiles(w http.ResponseWriter, r *http.Request) {
var (
vars = mux.Vars(r)
Expand Down Expand Up @@ -202,15 +202,6 @@ func GetMountFiles(w http.ResponseWriter, r *http.Request) {

select {
case <-done:
if err != nil {
errString := fmt.Sprintf("Error getting files in %s: %v", combinedPath, err)

plog.Error(errString)
http.Error(w, errString, http.StatusInternalServerError)

return
}

var files file.Files

for _, e := range dirEntries {
Expand All @@ -222,7 +213,13 @@ func GetMountFiles(w http.ResponseWriter, r *http.Request) {
files = append(files, file)
}

body, _ := json.Marshal(util.WithRoot("files", files))
resp := map[string]any {"error": "", "files": files }
if err != nil {
plog.Error(fmt.Sprintf("Error getting files in %s. Still read %d entries: %v", combinedPath, len(dirEntries), err))
resp["error"] = strings.Replace(fmt.Sprintf("%v", err), basePath, "", -1)
}

body, _ := json.Marshal(resp)
w.Write(body)
case <-time.After(2 * time.Second):
err := fmt.Sprintf("timeout getting files in %s", combinedPath)
Expand Down
2 changes: 1 addition & 1 deletion 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