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

server:

Fixed bug related to "vmstartwithcreds does not work anymore"
Bumped to version 1.11.2

clients:
Added new cmd: vmStartWithCreds but disabled for now (only for debugging purposes at the moment)
parent e00dd390
Branches
No related tags found
No related merge requests found
package cmdVM
import (
"encoding/json"
"nexus-client/exec"
"nexus-common/vm"
"nexus-common/params"
e "nexus-client/exec"
u "nexus-client/utils"
g "nexus-client/globals"
"github.com/go-playground/validator/v10"
)
type AttachFromPwd struct {
Name string
}
func (cmd *AttachFromPwd)GetName() string {
return cmd.Name
}
func (cmd *AttachFromPwd)GetDesc() []string {
return []string{
"Attaches to the VM that matches the specified password.",
"Requires the VM_ATTACH_ANY user capability."}
}
func (cmd *AttachFromPwd)PrintUsage() {
for _, desc := range cmd.GetDesc() {
u.PrintlnErr(desc)
}
u.PrintlnErr("―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――")
u.PrintlnErr("USAGE: ",cmd.GetName()," password")
u.PrintlnErr("―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――")
}
func (cmd *AttachFromPwd)Run(args []string) int {
if err := exec.CheckRemoteViewer(); err != nil {
u.PrintlnErr(err.Error())
return 1
}
argc := len(args)
if argc != 1 {
cmd.PrintUsage()
return 1
}
client := g.GetInstance().Client
host := g.GetInstance().Host
hostname := g.GetInstance().Hostname
cert := g.GetInstance().PubCert
pwd := args[0]
p := &params.VMAttachCreds{ Pwd: pwd }
resp, err := client.R().SetBody(p).Post(host+"/vms/spicecreds")
if err != nil {
u.PrintlnErr("Failed retrieving VM credentials: "+err.Error())
return 1
}
if resp.IsSuccess() {
var creds vm.VMSpiceCredentialsSerialized
if err := json.Unmarshal(resp.Body(), &creds); err != nil {
u.PrintlnErr("Failed deserializing VM spice credentials: "+err.Error())
return 1
}
if err := validator.New(validator.WithRequiredStructEnabled()).Struct(creds); err != nil {
u.PrintlnErr("Failed validating VM spice credentials: "+err.Error())
return 1
}
go func(creds vm.VMSpiceCredentialsSerialized) {
_, err := e.RunRemoteViewer(hostname, cert, creds.Name, creds.SpicePort, creds.SpicePwd, true)
if err != nil {
u.PrintlnErr("Failed executing remote-viewer: "+err.Error())
}
} (creds)
} else {
type msg struct {
Message string `json:"message"`
}
var m msg
if err := json.Unmarshal(resp.Body(), &m); err != nil {
u.PrintlnErr("Failed retrieving VM credentials: "+err.Error())
return 1
}
u.PrintlnErr("Failed retrieving VM credentials: "+m.Message)
return 1
}
return 0
}
...@@ -29,7 +29,7 @@ func (cmd *StartWithCreds)PrintUsage() { ...@@ -29,7 +29,7 @@ func (cmd *StartWithCreds)PrintUsage() {
u.PrintlnErr("USAGE: "+cmd.GetName()+" file.csv") u.PrintlnErr("USAGE: "+cmd.GetName()+" file.csv")
u.PrintlnErr("―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――") u.PrintlnErr("―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――")
const usage string = `file.csv 3-column CSV file defining the VMs to start and their credentials. const usage string = `file.csv 3-column CSV file defining the VMs to start and their credentials.
Content of the 3 columns: VM ID;VM name;password.` Content of the 3 columns: VM ID;VM name;password`
u.PrintlnErr(usage) u.PrintlnErr(usage)
} }
......
...@@ -46,10 +46,13 @@ var cmdList = []cmd.Command { ...@@ -46,10 +46,13 @@ var cmdList = []cmd.Command {
&cmdTemplate.Edit{"tpledit"}, &cmdTemplate.Edit{"tpledit"},
&cmdTemplate.ExportDisk{"tplexportdisk"}, &cmdTemplate.ExportDisk{"tplexportdisk"},
&cmdTemplate.List{"tpllist"}, &cmdTemplate.List{"tpllist"},
// &cmdTemplate.ListSingle{"tpllistsingle"}, // for testing the route only
&cmdMisc.HelpHeader{"!═════╡ VM commands ╞═════════════════════════════════════════════════════════════════"}, &cmdMisc.HelpHeader{"!═════╡ VM commands ╞═════════════════════════════════════════════════════════════════"},
&cmdVM.AddAccess{"vmaddaccess"}, &cmdVM.AddAccess{"vmaddaccess"},
&cmdVM.AttachAsync{"vmattach"}, &cmdVM.AttachAsync{"vmattach"},
// &cmdVM.AttachAsyncSingle{"vmattachsingle"}, // for testing the route only
// &cmdVM.AttachFromPwd{"vmattachfrompwd"}, // for testing the route only
&cmdVM.Create{"vmcreate"}, &cmdVM.Create{"vmcreate"},
&cmdVM.Creds2pdf{"vmcreds2pdf"}, &cmdVM.Creds2pdf{"vmcreds2pdf"},
&cmdVM.Creds2csv{"vmcreds2csv"}, &cmdVM.Creds2csv{"vmcreds2csv"},
...@@ -60,6 +63,7 @@ var cmdList = []cmd.Command { ...@@ -60,6 +63,7 @@ var cmdList = []cmd.Command {
&cmdVM.ImportDir{"vmimportdir"}, &cmdVM.ImportDir{"vmimportdir"},
&cmdVM.Stop{"vmkill"}, &cmdVM.Stop{"vmkill"},
&cmdVM.List{"vmlist"}, &cmdVM.List{"vmlist"},
// &cmdVM.ListSingle{"vmlistsingle"}, // for testing the route only
&cmdVM.Reboot{"vmreboot"}, &cmdVM.Reboot{"vmreboot"},
&cmdVM.Shutdown{"vmshutdown"}, &cmdVM.Shutdown{"vmshutdown"},
&cmdVM.Start{"vmstart"}, &cmdVM.Start{"vmstart"},
......
...@@ -58,6 +58,7 @@ var cmdList = []cmd.Command { ...@@ -58,6 +58,7 @@ var cmdList = []cmd.Command {
&cmdVM.AddAccess{"vmaddaccess"}, &cmdVM.AddAccess{"vmaddaccess"},
&cmdVM.AttachAsync{"vmattach"}, &cmdVM.AttachAsync{"vmattach"},
// &cmdVM.AttachAsyncSingle{"vmattachsingle"}, // for testing the route only // &cmdVM.AttachAsyncSingle{"vmattachsingle"}, // for testing the route only
// &cmdVM.AttachFromPwd{"vmattachfrompwd"}, // for testing the route only
&cmdVM.Create{"vmcreate"}, &cmdVM.Create{"vmcreate"},
&cmdVM.Creds2pdf{"vmcreds2pdf"}, &cmdVM.Creds2pdf{"vmcreds2pdf"},
&cmdVM.Creds2csv{"vmcreds2csv"}, &cmdVM.Creds2csv{"vmcreds2csv"},
......
...@@ -203,6 +203,7 @@ func (r *RouterVMs)VMSpiceCreds(c echo.Context) error { ...@@ -203,6 +203,7 @@ func (r *RouterVMs)VMSpiceCreds(c echo.Context) error {
} }
// Returns the Spice credentials for the VM matching the specific VM attach password. // Returns the Spice credentials for the VM matching the specific VM attach password.
// Output: nexus-common/vm.VMSpiceCredentialsSerialized
// Requires the CAP_VM_ATTACH_ANY user capability: // Requires the CAP_VM_ATTACH_ANY user capability:
// curl --cacert ca.pem -X POST https://localhost:1077/vms/spicecreds -H 'Content-Type: application/json' -d '{"pwd":"46L8drgZ5Dx"}' -H "Authorization: Bearer <AccessToken>" // curl --cacert ca.pem -X POST https://localhost:1077/vms/spicecreds -H 'Content-Type: application/json' -d '{"pwd":"46L8drgZ5Dx"}' -H "Authorization: Bearer <AccessToken>"
func (r *RouterVMs)VMSpiceCredsAny(c echo.Context) error { func (r *RouterVMs)VMSpiceCredsAny(c echo.Context) error {
......
...@@ -7,7 +7,7 @@ import ( ...@@ -7,7 +7,7 @@ import (
const ( const (
major = 1 major = 1
minor = 11 minor = 11
bugfix = 1 bugfix = 2
) )
var version params.Version = params.NewVersion(major, minor, bugfix) var version params.Version = params.NewVersion(major, minor, bugfix)
......
...@@ -161,6 +161,7 @@ func (vms *VMs)GetVM(vmID uuid.UUID) (*VM, error) { ...@@ -161,6 +161,7 @@ func (vms *VMs)GetVM(vmID uuid.UUID) (*VM, error) {
func (vms *VMs)GetVMByPwd(pwd string) (*VM, error) { func (vms *VMs)GetVMByPwd(pwd string) (*VM, error) {
vms.rwlock.RLock() vms.rwlock.RLock()
defer vms.rwlock.RUnlock() defer vms.rwlock.RUnlock()
vmID, exists := vms.pwdToVM[pwd] vmID, exists := vms.pwdToVM[pwd]
if !exists { if !exists {
return nil, errors.New("VM not found") return nil, errors.New("VM not found")
...@@ -242,9 +243,16 @@ func (vms *VMs)prepareStartVM(vmID uuid.UUID, attachPwd string) (*osexec.Cmd, *V ...@@ -242,9 +243,16 @@ func (vms *VMs)prepareStartVM(vmID uuid.UUID, attachPwd string) (*osexec.Cmd, *V
// Randomly generates a unique password used to attach to the VM // Randomly generates a unique password used to attach to the VM
if attachPwd == "" { if attachPwd == "" {
attachPwd, err = vms.allocateAttachPwd(vmID) attachPwd, err = vms.allocateRandomAttachPwd(vmID)
if err != nil { if err != nil {
msg := prefix+vmID.String()+": attach password generation error: "+err.Error() msg := prefix+vmID.String()+": attach password allocation error: "+err.Error()
log.Error(msg)
return nil, nil, "", 0, 0, errors.New(msg)
}
} else {
err = vms.allocateAttachPwd(attachPwd, vmID)
if err != nil {
msg := prefix+vmID.String()+": attach password allocation error: "+err.Error()
log.Error(msg) log.Error(msg)
return nil, nil, "", 0, 0, errors.New(msg) return nil, nil, "", 0, 0, errors.New(msg)
} }
...@@ -442,10 +450,11 @@ func (vms *VMs)freeSpiceRandomPort(port int) { ...@@ -442,10 +450,11 @@ func (vms *VMs)freeSpiceRandomPort(port int) {
vms.usedPorts[port] = false vms.usedPorts[port] = false
} }
// Randomly generates a unique password as credentials to attach to a VM. // Randomly generates a unique password and reserve it for the specified VM.
// This password can be used as credentials to access the associated VM.
// Returns the generated password. // Returns the generated password.
// Concurrency: safe // Concurrency: safe
func (vms *VMs)allocateAttachPwd(vmID uuid.UUID) (string, error) { func (vms *VMs)allocateRandomAttachPwd(vmID uuid.UUID) (string, error) {
vms.mutexPwdToVM.Lock() vms.mutexPwdToVM.Lock()
defer vms.mutexPwdToVM.Unlock() defer vms.mutexPwdToVM.Unlock()
...@@ -463,6 +472,20 @@ func (vms *VMs)allocateAttachPwd(vmID uuid.UUID) (string, error) { ...@@ -463,6 +472,20 @@ func (vms *VMs)allocateAttachPwd(vmID uuid.UUID) (string, error) {
} }
} }
// Reserve the specified password as credentials to access the specified VM.
// Concurrency: safe
func (vms *VMs)allocateAttachPwd(attachPwd string, vmID uuid.UUID) error {
vms.mutexPwdToVM.Lock()
defer vms.mutexPwdToVM.Unlock()
_, exists := vms.pwdToVM[attachPwd]
if exists {
return errors.New("vms.allocateAttachPwd: password already reserved!")
}
vms.pwdToVM[attachPwd] = vmID
return nil
}
// Frees a password that was previously allocated with allocateAttachPwd(). // Frees a password that was previously allocated with allocateAttachPwd().
// Concurrency: safe // Concurrency: safe
func (vms *VMs)freeAttachPwd(attachPwd string) { func (vms *VMs)freeAttachPwd(attachPwd string) {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment