Skip to content
Snippets Groups Projects
Commit 6c54feae authored by Florent Gluck's avatar Florent Gluck
Browse files

server and client: created structures in common to store REST arguments

fixed a serious bug where ports used by VMs were not being marked as free again!
added more tests to validate script
bumped server version to 1.8.1
bumped client version to 1.8.1
parent 66ce54d9
Branches
No related tags found
No related merge requests found
Showing
with 189 additions and 132 deletions
package cmdTemplate
import (
"nexus-common/params"
u "nexus-client/utils"
g "nexus-client/globals"
"github.com/google/uuid"
......@@ -65,15 +66,8 @@ func (cmd *Create)makeRequestForID(vmID uuid.UUID, name, access string) (*resty.
client := g.GetInstance().Client
host := g.GetInstance().Host
type TemplateArgs struct {
VMID uuid.UUID
Name string
Access string
}
templateArgs := &TemplateArgs { vmID, name, access }
resp, err := client.R().SetBody(templateArgs).Post(host+"/templates/vm")
p := &params.TplCreate{ vmID, name, access }
resp, err := client.R().SetBody(p).Post(host+"/templates/vm")
if err != nil {
return nil, err
}
......
......@@ -3,6 +3,7 @@ package cmdTemplate
import (
"errors"
"strings"
"nexus-common/params"
u "nexus-client/utils"
g "nexus-client/globals"
)
......@@ -11,11 +12,6 @@ type Edit struct {
Name string
}
type templateEditParameters struct {
Name string
Access string
}
func (cmd *Edit)GetName() string {
return cmd.Name
}
......@@ -49,13 +45,13 @@ func (cmd *Edit)Run(args []string) int {
return 1
}
templateParams, err := cmd.parseArgs(args[1:])
p, err := cmd.parseArgs(args[1:])
if err != nil {
u.PrintlnErr(err.Error())
return 1
}
if templateParams == nil {
if p == nil {
cmd.PrintUsage()
return 1
}
......@@ -63,7 +59,7 @@ func (cmd *Edit)Run(args []string) int {
tplID := args[0]
statusCode := 0
resp, err := client.R().SetBody(templateParams).Put(host+"/templates/"+tplID)
resp, err := client.R().SetBody(p).Put(host+"/templates/"+tplID)
if err != nil {
u.PrintlnErr("Failed editing template \""+tplID+"\": "+err.Error())
statusCode = 1
......@@ -79,8 +75,8 @@ func (cmd *Edit)Run(args []string) int {
return statusCode
}
func (cmd *Edit)parseArgs(args []string) (*templateEditParameters, error) {
templateParams := &templateEditParameters {}
func (cmd *Edit)parseArgs(args []string) (*params.TplCreate, error) {
p := &params.TplCreate{}
atLeastOneArg := false
getStringVal := func(s string, prefix string) string {
......@@ -94,13 +90,13 @@ func (cmd *Edit)parseArgs(args []string) (*templateEditParameters, error) {
for _, arg := range args {
s := getStringVal(arg, "name=")
if s != "" {
templateParams.Name = s
p.Name = s
atLeastOneArg = true
continue
}
s = getStringVal(arg, "access=")
if s != "" {
templateParams.Access = s
p.Access = s
atLeastOneArg = true
continue
}
......@@ -108,7 +104,7 @@ func (cmd *Edit)parseArgs(args []string) (*templateEditParameters, error) {
}
if atLeastOneArg {
return templateParams, nil
return p, nil
} else {
return nil, nil
}
......
......@@ -6,6 +6,7 @@ import (
"errors"
"strings"
"encoding/csv"
"nexus-common/params"
u "nexus-client/utils"
g "nexus-client/globals"
)
......@@ -38,10 +39,6 @@ func (cmd *SetCaps)PrintUsage() {
u.PrintlnErr(usage)
}
type capsArgs struct {
Caps map[string]int `json:"caps" validate:"required"`
}
func (cmd *SetCaps)Run(args []string) int {
argc := len(args)
if argc < 1 {
......@@ -88,7 +85,7 @@ func (cmd *SetCaps)Run(args []string) int {
continue
}
userCaps := &capsArgs { make(map[string]int) }
userCaps := &params.UserSetCaps{ make(map[string]int) }
capsStr := strings.TrimSpace(columns[1])
if len(capsStr) > 0 {
......@@ -114,10 +111,9 @@ func (cmd *SetCaps)Run(args []string) int {
}
} else {
// Argument is an email address
email := args[0]
userCaps := &capsArgs { make(map[string]int) }
userCaps := &params.UserSetCaps{ make(map[string]int) }
for _, cap := range args[1:] {
userCaps.Caps[cap] = 1
}
......@@ -133,7 +129,7 @@ func (cmd *SetCaps)Run(args []string) int {
return statusCode
}
func (cmd *SetCaps)runRequest(email string, userCaps *capsArgs) error {
func (cmd *SetCaps)runRequest(email string, userCaps *params.UserSetCaps) error {
client := g.GetInstance().Client
host := g.GetInstance().Host
......
package cmdUser
import (
"nexus-common/params"
u "nexus-client/utils"
g "nexus-client/globals"
)
......@@ -64,13 +65,8 @@ func (cmd *UpdatePwd)Run(args []string) int {
}
pwdStr := string(newPwd)
type PwdArgs struct {
Pwd string
}
pwdArgs := &PwdArgs{pwdStr}
resp, err := client.R().SetBody(pwdArgs).Put(host+"/users/pwd")
p := &params.UserSetPwd{pwdStr}
resp, err := client.R().SetBody(p).Put(host+"/users/pwd")
if err != nil {
u.PrintlnErr("Error: "+err.Error())
return 1
......
......@@ -4,6 +4,8 @@ go 1.18
replace nexus-common/caps => ../../common/caps
replace nexus-common/params => ../../common/params
replace nexus-common/vm => ../../common/vm
replace nexus-common/template => ../../common/template
......@@ -58,6 +60,7 @@ require (
nexus-client/exec v0.0.0-00010101000000-000000000000 // indirect
nexus-client/version v0.0.0-00010101000000-000000000000 // indirect
nexus-common/caps v0.0.0-00010101000000-000000000000 // indirect
nexus-common/params v0.0.0-00010101000000-000000000000 // indirect
nexus-common/template v0.0.0-00010101000000-000000000000 // indirect
nexus-common/utils v0.0.0-00010101000000-000000000000 // indirect
nexus-common/vm v0.0.0-00010101000000-000000000000 // indirect
......
......@@ -6,11 +6,13 @@ nexus_cli="./nexus-cli"
partial_name="exam 328a2d0eff08"
full_name="live $partial_name"
creds_file=creds.pdf
creds_pdf_file=creds.pdf
creds_csv_file=creds.csv
del_gen_files () {
find . -name "$full_name *.tar.gz" -delete
rm -f $creds_file
rm -f $creds_pdf_file
rm -f $creds_csv_file
}
cleanup () {
......@@ -90,9 +92,14 @@ check "vmstart VMs"
sleep 3
OK
echo "Generate credentials pdf..."
$nexus_cli vmcred2pdf "$full_name" $creds_file
check "vmcred2pdf"
echo "Generate credentials to PDF..."
$nexus_cli vmcreds2pdf "$full_name" $creds_pdf_file
check "vmcreds2pdf"
OK
echo "Generate credentials to CSV..."
$nexus_cli vmcreds2csv "$full_name" $creds_csv_file
check "vmcreds2csv"
OK
echo "Kill students VMs..."
......@@ -106,6 +113,18 @@ $nexus_cli vmexportdir "$full_name" /home
check "vmexportdir"
OK
echo "Re-start students VMs with previous credentials..."
$nexus_cli vmstartwithcreds $creds_csv_file
check "vmstartwithcreds VMs"
sleep 10
OK
echo "Kill students VMs..."
$nexus_cli vmkill "$full_name"
sleep 3
check "vmkill VMs"
OK
echo "Delete students VMs..."
$nexus_cli vmdel "$partial_name"
check "vmdel VMs"
......
......@@ -4,6 +4,8 @@ go 1.18
replace nexus-common/caps => ../../common/caps
replace nexus-common/params => ../../common/params
replace nexus-common/vm => ../../common/vm
replace nexus-common/template => ../../common/template
......@@ -60,6 +62,7 @@ require (
nexus-client/utils v0.0.0-00010101000000-000000000000 // indirect
nexus-client/version v0.0.0-00010101000000-000000000000 // indirect
nexus-common/caps v0.0.0-00010101000000-000000000000 // indirect
nexus-common/params v0.0.0-00010101000000-000000000000 // indirect
nexus-common/template v0.0.0-00010101000000-000000000000 // indirect
nexus-common/utils v0.0.0-00010101000000-000000000000 // indirect
nexus-common/vm v0.0.0-00010101000000-000000000000 // indirect
......
......@@ -8,7 +8,7 @@ import (
const (
major = 1
minor = 8
bugfix = 0
bugfix = 1
)
type Version struct {
......
module nexus-common/params
go 1.18
package params
import (
"github.com/google/uuid"
)
type TplCreate struct {
VMID uuid.UUID `json:"vmID" validate:"required"`
Name string `json:"name" validate:"required,min=2"`
Access string `json:"access" validate:"required,min=4"`
}
type TplEdit struct {
Name string `json:"name"`
Access string `json:"access"`
}
package params
import (
"nexus-common/caps"
)
type UserSetCaps struct {
Caps caps.Capabilities
}
type UserSetPwd struct {
Pwd string `json:"pwd" validate:"required,min=8"`
}
package params
import (
"nexus-common/vm"
"nexus-common/caps"
"github.com/google/uuid"
)
type VMCreate struct {
Name string `json:"name" validate:"required,min=4,max=256"`
Cpus int `json:"cpus" validate:"required,gte=1,lte=16"`
Ram int `json:"ram" validate:"required,gte=512,lte=32768"`
Nic vm.NicType `json:"nic" validate:"required`
UsbDevs []string `json:"usbDevs" validate:"required`
TemplateID uuid.UUID `json:"templateID" validate:"required"`
}
type VMStartWithCreds struct {
Port int `json:"port" validate:"required,gte=1100,lte=65535"`
Pwd string `json:"pwd" validate:"required,min=8,max=64"`
}
type VMEdit struct {
Name string `json:"name" validate:"required,min=4,max=256"`
Cpus int `json:"cpus" validate:"required,gte=1,lte=16"`
Ram int `json:"ram" validate:"required,gte=512,lte=32768"`
Nic vm.NicType `json:"nic" validate:"required`
UsbDevs []string `json:"usbDevs" validate:"required`
}
type VMAddAccess struct {
Access caps.Capabilities `json:"access" validate:"required"`
}
type VMExportDir struct {
Dir string `json:"dir"`
}
......@@ -6,6 +6,8 @@ replace nexus-common/template => ../common/template
replace nexus-common/vm => ../common/vm
replace nexus-common/params => ../common/params
replace nexus-common/caps => ../common/caps
replace nexus-server/consts => ./consts
......@@ -62,6 +64,7 @@ require (
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 // indirect
nexus-common/caps v0.0.0-00010101000000-000000000000 // indirect
nexus-common/params v0.0.0-00010101000000-000000000000 // indirect
nexus-common/template v0.0.0-00010101000000-000000000000 // indirect
nexus-common/vm v0.0.0-00010101000000-000000000000 // indirect
nexus-server/exec v0.0.0-00010101000000-000000000000 // indirect
......
......@@ -6,6 +6,7 @@ import (
"net/http"
"path/filepath"
"nexus-common/caps"
"nexus-common/params"
"nexus-server/vms"
"nexus-server/paths"
"nexus-server/users"
......@@ -66,13 +67,8 @@ func (r *RouterTemplates)CreateTemplateFromVM(c echo.Context) error {
return echo.NewHTTPError(http.StatusUnauthorized, msgInsufficientCaps)
}
// Deserializes and validates the client's parameters.
type Parameters struct {
VMID uuid.UUID `json:"vmID" validate:"required"`
Name string `json:"name" validate:"required,min=2"`
Access string `json:"access" validate:"required,min=4"`
}
p := new(Parameters)
// Deserializes and validates client's parameters.
p := new(params.TplCreate)
if err := decodeJson(c, &p); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, err.Error())
}
......@@ -243,14 +239,10 @@ func (r *RouterTemplates)EditTemplateByID(c echo.Context) error {
return echo.NewHTTPError(http.StatusBadRequest, err.Error())
}
// Deserializes and validates the client's parameters.
// Deserializes and validates client's parameters.
// Given these parameters are optional, we can't use a validator on them.
// Validation is performed in templates.EditTemplate() instead.
type Parameters struct {
Name string `json:"name"`
Access string `json:"access"`
}
p := new(Parameters)
p := new(params.TplEdit)
if user.HasCapability(caps.CAP_TPL_EDIT_ANY) {
if err := decodeJson(c, &p); err != nil {
......
......@@ -3,6 +3,7 @@ package router
import (
"net/http"
"nexus-common/caps"
"nexus-common/params"
"nexus-server/users"
"nexus-server/utils"
"github.com/labstack/echo/v4"
......@@ -128,18 +129,14 @@ func (r *RouterUsers) SetUserCaps(c echo.Context) error {
return echo.NewHTTPError(http.StatusUnauthorized, msgInsufficientCaps)
}
// Deserializes and validates the client's parameters.
type Parameters struct {
Caps caps.Capabilities
}
params := &Parameters{make(caps.Capabilities)}
if err := decodeJson(c, &params); err != nil {
// Deserializes and validates client's parameters.
p := new(params.UserSetCaps)
if err := decodeJson(c, &p); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, err.Error())
}
// Checks capabilities are valid.
if err := caps.ValidateUserCaps(params.Caps); err != nil {
if err := caps.ValidateUserCaps(p.Caps); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, err.Error())
}
......@@ -150,7 +147,7 @@ func (r *RouterUsers) SetUserCaps(c echo.Context) error {
}
// Updates the user's capabilities.
userToUpdate.Caps = params.Caps
userToUpdate.Caps = p.Caps
// Updates user and saves the new user file.
if err = r.users.UpdateUser(&userToUpdate); err != nil {
......@@ -163,19 +160,14 @@ func (r *RouterUsers) SetUserCaps(c echo.Context) error {
// Update the logged user's password.
// curl --cacert ca.pem -X PUT http://localhost:1077/users/pwd -H 'Content-Type: application/json' -d '{"pwd": "new_password"}' -H "Authorization: Bearer <AccessToken>"
func (r *RouterUsers) SetUserPwd(c echo.Context) error {
// Deserializes the client's parameters.
type Parameters struct {
Pwd string `json:"pwd" validate:"required,min=8"`
}
params := &Parameters{}
// Deserializes the JSON body and checks its validity.
if err := decodeJson(c, &params); err != nil {
// Deserializes and validates client's parameters.
p := new(params.UserSetPwd)
if err := decodeJson(c, &p); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, err.Error())
}
// Checks the new password is valid.
if err := validator.New().Struct(params); err != nil {
if err := validator.New().Struct(p); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, err.Error())
}
......@@ -186,7 +178,7 @@ func (r *RouterUsers) SetUserPwd(c echo.Context) error {
}
// Hashes and udpates the user's password.
user.Pwd = utils.HashPassword(params.Pwd)
user.Pwd = utils.HashPassword(p.Pwd)
// Updates user and saves the new user file.
if err = r.users.UpdateUser(user); err != nil {
......
......@@ -6,7 +6,7 @@ import (
"net/http"
"path/filepath"
"nexus-common/caps"
vmc "nexus-common/vm"
"nexus-common/params"
"nexus-server/vms"
"nexus-server/users"
"nexus-server/paths"
......@@ -179,15 +179,7 @@ func (r *RouterVMs)CreateVM(c echo.Context) error {
}
// Deserializes and validates client's parameters.
type Parameters struct {
Name string `json:"name" validate:"required,min=4,max=256"`
Cpus int `json:"cpus" validate:"required,gte=1,lte=16"`
Ram int `json:"ram" validate:"required,gte=512,lte=32768"`
Nic vmc.NicType `json:"nic" validate:"required`
UsbDevs []string `json:"usbDevs" validate:"required`
TemplateID uuid.UUID `json:"templateID" validate:"required"`
}
p := new(Parameters)
p := new(params.VMCreate)
if err := decodeJson(c, &p); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, err.Error())
}
......@@ -243,16 +235,12 @@ func (r *RouterVMs)StartVMWithCreds(c echo.Context) error {
return r.performVMAction(c, caps.CAP_VM_START_ANY, caps.CAP_VM_START, func(c echo.Context, vm *vms.VM) error {
// Deserializes and validates client's parameters.
type Parameters struct {
Port int `json:"port" validate:"required,gte=1100,lte=65535"`
Pwd string `json:"pwd" validate:"required,min=8,max=64"`
}
p := new(Parameters)
p := new(params.VMStartWithCreds)
if err := decodeJson(c, &p); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, err.Error())
}
if err := r.vms.StartVMWithCreds(vm.GetID(), p.Port, p.Pwd); err != nil {
if err := r.vms.StartVMWithCreds(vm.GetID(), p.Port, true, p.Pwd); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, err.Error())
}
return c.JSONPretty(http.StatusOK, jsonMsg("OK"), " ")
......@@ -308,17 +296,10 @@ func (r *RouterVMs)RebootVM(c echo.Context) error {
// curl --cacert ca.pem -X PUT https://localhost:1077/vms/e41f3556-ca24-4658-bd79-8c85bd6bff59 -H 'Content-Type: application/json' -d '{"name":"Edited VM","cpus":1,"ram":2048,"nic":"user","usbDevs":["1307:0165","1234:abcd"]}' -H "Authorization: Bearer <AccessToken>"
func (r *RouterVMs)EditVMByID(c echo.Context) error {
return r.performVMAction(c, caps.CAP_VM_EDIT_ANY, caps.CAP_VM_EDIT, func(c echo.Context, vm *vms.VM) error {
// Deserializes and validates the client's parameters.
// Deserializes and validates client's parameters.
// Given these parameters are optional, we can't use a validator on them.
// Validation is performed in vm.EditVM() instead.
type Parameters struct {
Name string `json:"name" validate:"required,min=4,max=256"`
Cpus int `json:"cpus" validate:"required,gte=1,lte=16"`
Ram int `json:"ram" validate:"required,gte=512,lte=32768"`
Nic vmc.NicType `json:"nic" validate:"required`
UsbDevs []string `json:"usbDevs" validate:"required`
}
p := new(Parameters)
p := new(params.VMEdit)
if err := decodeJson(c, &p); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, err.Error())
}
......@@ -368,19 +349,16 @@ func (r *RouterVMs)SetVMAccessForUser(c echo.Context) error {
}
}
// Deserializes and validates the client's parameters.
type Parameters struct {
Access caps.Capabilities `json:"access" validate:"required"`
}
params := new(Parameters)
if err := decodeJson(c, &params); err != nil {
// Deserializes and validates client's parameters.
p := new(params.VMAddAccess)
if err := decodeJson(c, &p); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, err.Error())
}
if err := validator.New().Struct(params); err != nil {
if err := validator.New().Struct(p); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, err.Error())
}
if err = r.vms.SetVMAccess(vmID, user.Email, email, params.Access); err != nil {
if err = r.vms.SetVMAccess(vmID, user.Email, email, p.Access); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, err.Error())
}
......@@ -438,10 +416,7 @@ func (r *RouterVMs)DeleteVMAccessForUser(c echo.Context) error {
func (r *RouterVMs)ExportVMDir(c echo.Context) error {
return r.performVMAction(c, caps.CAP_VM_READFS_ANY, caps.CAP_VM_READFS, func(c echo.Context, vm *vms.VM) error {
// Deserializes and validates the client's parameter.
type Parameters struct {
Dir string `json:"dir"`
}
p := new(Parameters)
p := new(params.VMExportDir)
if err := decodeJson(c, &p); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, err.Error())
}
......
......@@ -7,7 +7,7 @@ import (
const (
major = 1
minor = 8
bugfix = 0
bugfix = 1
)
type Version struct {
......
......@@ -90,6 +90,7 @@ func InitVMs() error {
// Returns the list of serialized VMs for which VMKeeperFn returns true.
func (vms *VMs)GetNetworkSerializedVMs(keepFn VMKeeperFn) []vm.VMNetworkSerialized {
vms.rwlock.RLock()
list := []vm.VMNetworkSerialized{}
for _, vm := range vms.m {
vm.mutex.Lock()
......@@ -173,16 +174,12 @@ func (vms *VMs)AddVM(vm *VM) error {
}
// Starts a VM by its ID, using the specified port and password.
func (vms *VMs)StartVMWithCreds(vmID uuid.UUID, port int, pwd string) error {
// If checkPort is true, a check is performed on the specified port and if it is already
// in use, the function fails and returns a corresponding error.
func (vms *VMs)StartVMWithCreds(vmID uuid.UUID, port int, checkPort bool, pwd string) error {
vms.rwlock.Lock()
defer vms.rwlock.Unlock()
if vms.usedPorts[port] || !utils.IsPortAvailable(port) {
return errors.New("Failed starting VM: port already in use")
} else {
vms.usedPorts[port] = true
}
vm, err := vms.getVMUnsafe(vmID)
if err != nil {
return err
......@@ -195,8 +192,21 @@ func (vms *VMs)StartVMWithCreds(vmID uuid.UUID, port int, pwd string) error {
return errors.New("Failed starting VM: VM already running")
}
if checkPort {
if vms.usedPorts[port] {
return errors.New("Failed starting VM: port already in use")
} else if !utils.IsPortAvailable(port) {
return errors.New("Failed starting VM: port not available")
} else {
vms.usedPorts[port] = true
}
} else {
vms.usedPorts[port] = true
}
totalRAM, availRAM, err := utils.GetRAM()
if err != nil {
vms.usedPorts[port] = false
return errors.New("Failed starting VM: failed obtaining memory info: "+err.Error())
}
......@@ -209,42 +219,51 @@ func (vms *VMs)StartVMWithCreds(vmID uuid.UUID, port int, pwd string) error {
// otherwise, refuses to run it in order to avoid RAM saturation.
if availRAM - vms.usedRAM <= int(math.Round(float64(totalRAM)*(1.-c.RamUsageLimit))) {
vms.usedRAM -= estimatedVmRAM
vms.usedPorts[port] = false
return errors.New("Failed starting VM: insufficient free RAM")
}
// This callback is called once the VM started with vm.start terminates.
endofExecFn := func (vm *VM) {
vms.rwlock.Lock()
vms.usedPorts[port] = false
vms.usedRAM -= estimatedVmRAM
vms.rwlock.Unlock()
vm.mutex.Lock()
vm.removeSecretFile()
vm.resetStates()
vm.mutex.Unlock()
vms.rwlock.Lock()
vms.usedPorts[vm.Run.Port] = false
vms.usedRAM -= estimatedVmRAM
vms.rwlock.Unlock()
}
if err = vm.start(port, pwd, endofExecFn); err != nil {
vms.usedPorts[port] = false
return err
}
return nil
}
// Starts a VM by its ID using randomly generated port number and password.
// Returns the port on which the VM is running and the access password.
func (vms *VMs)StartVM(vmID uuid.UUID) (int, string, error) {
// Allocates and returns a free port randomly chosen between VMSpiceMinPort and
// VMSpiceMaxPort (inclusive).
// Beware: this function updates the vms map.
func (vms *VMs)allocateFreeRandomPort() int {
vms.rwlock.Lock()
defer vms.rwlock.Unlock()
// Locates a free port randomly chosen between VMSpiceMinPort and VMSpiceMaxPort (inclusive).
var port int
for {
port = utils.Rand(c.VMSpiceMinPort, c.VMSpiceMaxPort)
port := utils.Rand(c.VMSpiceMinPort, c.VMSpiceMaxPort)
if !vms.usedPorts[port] {
if utils.IsPortAvailable(port) {
vms.usedPorts[port] = true
break
return port
}
}
}
}
// Starts a VM by its ID using randomly generated port number and password.
// Returns the port on which the VM is running and the access password.
func (vms *VMs)StartVM(vmID uuid.UUID) (int, string, error) {
port := vms.allocateFreeRandomPort()
// Randomly generates a 8 characters long password with 4 digits, 0 symbols,
// allowing upper and lower case letters, disallowing repeat characters.
......@@ -254,7 +273,7 @@ func (vms *VMs)StartVM(vmID uuid.UUID) (int, string, error) {
return -1, "", errors.New("Failed starting VM: password generation error: "+err.Error())
}
if err = vms.StartVMWithCreds(vmID, port, pwd); err != nil {
if err = vms.StartVMWithCreds(vmID, port, false, pwd); err != nil {
return -1, "", err
}
return port, pwd, nil
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment