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

libclient: WIP, but almost completed

parent 3a3996fc
No related branches found
No related tags found
No related merge requests found
package cmdVM package cmdVM
import ( import (
"encoding/json"
"errors"
"fmt" "fmt"
"nexus-client/exec" "nexus-client/exec"
u "nexus-client/utils" u "nexus-client/utils"
"nexus-common/params" "nexus-common/params"
"nexus-common/vm" "nexus-common/vm"
g "nexus-libclient/globals" g "nexus-libclient/globals"
"sync" libclient "nexus-libclient/vm"
"github.com/go-playground/validator/v10"
) )
// The boolean indicates whether attaching is blocking (synchronous) or non-blocking (asynchronous). func AttachToVMs(vms []vm.VMAttachCredentialsSerialized) (int, error) {
func AttachToVMs(vms []vm.VMAttachCredentialsSerialized, synchronous bool) (int, error) {
statusCode := 0 statusCode := 0
hostname := g.GetInstance().Hostname hostname := g.GetInstance().Hostname
cert := g.GetInstance().PubCert cert := g.GetInstance().PubCert
client := g.GetInstance().Client
host := g.GetInstance().Host
var wg sync.WaitGroup
if synchronous {
// Use wait groups to wait until all viewers threads have completed.
wg.Add(len(vms))
}
for _, v := range vms { for _, v := range vms {
uuid := v.ID.String() p := params.VMAttachCreds{Pwd: v.Pwd}
p := &params.VMAttachCreds{Pwd: v.Pwd}
resp, err := client.R().SetBody(p).Post(host + "/vms/" + uuid + "/spicecreds")
if err != nil {
return 1, err
}
if resp.IsSuccess() { creds, err := libclient.VMGetSpiceCreds(v.ID.String(), p)
var creds vm.VMSpiceCredentialsSerialized if err != nil {
if err := json.Unmarshal(resp.Body(), &creds); err != nil { u.PrintlnErr(err)
return 1, err
}
if err := validator.New(validator.WithRequiredStructEnabled()).Struct(creds); err != nil {
return 1, err return 1, err
} }
...@@ -54,18 +31,7 @@ func AttachToVMs(vms []vm.VMAttachCredentialsSerialized, synchronous bool) (int, ...@@ -54,18 +31,7 @@ func AttachToVMs(vms []vm.VMAttachCredentialsSerialized, synchronous bool) (int,
u.PrintlnErr("Failed attaching to VM ", v.ID, ": ", fmt.Sprintf("%s", stdoutStderr)) u.PrintlnErr("Failed attaching to VM ", v.ID, ": ", fmt.Sprintf("%s", stdoutStderr))
statusCode |= 1 statusCode |= 1
} }
if synchronous { }(v, *creds)
wg.Done()
}
}(v, creds)
} else {
return 1, errors.New(resp.Status() + ": " + resp.String())
}
}
if synchronous {
wg.Wait()
} }
return statusCode, nil return statusCode, nil
......
...@@ -108,7 +108,7 @@ func getFilteredVMs(filteredVMsFunc GetVMs, patterns []string) ([]vm.VMNetworkSe ...@@ -108,7 +108,7 @@ func getFilteredVMs(filteredVMsFunc GetVMs, patterns []string) ([]vm.VMNetworkSe
// //
// "." -> matches everything // "." -> matches everything
// "bla" -> matches any VM name containing "bla" // "bla" -> matches any VM name containing "bla"
func getFilteredVMCredentials(route string, patterns []string) ([]vm.VMAttachCredentialsSerialized, error) { func getFilteredVMCredentials(patterns []string) ([]vm.VMAttachCredentialsSerialized, error) {
if len(patterns) < 1 { if len(patterns) < 1 {
return nil, errors.New("At least one ID or regex must be specified") return nil, errors.New("At least one ID or regex must be specified")
} }
......
...@@ -36,7 +36,7 @@ func (cmd *AttachAsync) Run(args []string) int { ...@@ -36,7 +36,7 @@ func (cmd *AttachAsync) Run(args []string) int {
return 1 return 1
} }
creds, err := getFilteredVMCredentials("/vms/attach", args) creds, err := getFilteredVMCredentials(args)
if err != nil { if err != nil {
u.PrintlnErr(err) u.PrintlnErr(err)
return 1 return 1
...@@ -47,7 +47,7 @@ func (cmd *AttachAsync) Run(args []string) int { ...@@ -47,7 +47,7 @@ func (cmd *AttachAsync) Run(args []string) int {
return 1 return 1
} }
statusCode, err := AttachToVMs(creds, false) statusCode, err := AttachToVMs(creds)
if err != nil { if err != nil {
u.PrintlnErr(err) u.PrintlnErr(err)
} }
......
...@@ -50,7 +50,7 @@ func (cmd *AttachAsyncSingle) Run(args []string) int { ...@@ -50,7 +50,7 @@ func (cmd *AttachAsyncSingle) Run(args []string) int {
return 1 return 1
} }
statusCode, err := AttachToVMs([]vm.VMAttachCredentialsSerialized{*creds}, false) statusCode, err := AttachToVMs([]vm.VMAttachCredentialsSerialized{*creds})
if err != nil { if err != nil {
u.PrintlnErr(err) u.PrintlnErr(err)
return 1 return 1
......
package cmdVM package cmdVM
import ( import (
"encoding/json"
"nexus-client/exec" "nexus-client/exec"
e "nexus-client/exec" e "nexus-client/exec"
u "nexus-client/utils" u "nexus-client/utils"
"nexus-common/params" "nexus-common/params"
"nexus-common/vm" "nexus-common/vm"
g "nexus-libclient/globals" g "nexus-libclient/globals"
libclient "nexus-libclient/vm"
"github.com/go-playground/validator/v10"
) )
type AttachFromPwd struct { type AttachFromPwd struct {
...@@ -23,7 +21,7 @@ func (cmd *AttachFromPwd) GetName() string { ...@@ -23,7 +21,7 @@ func (cmd *AttachFromPwd) GetName() string {
func (cmd *AttachFromPwd) GetDesc() []string { func (cmd *AttachFromPwd) GetDesc() []string {
return []string{ return []string{
"Attaches to the VM that matches the specified password.", "Attaches to the VM that matches the specified password.",
"Requires the VM_ATTACH_ANY user capability."} "Requires either EXAM_ATTACH or VM_ATTACH_ANY user capability."}
} }
func (cmd *AttachFromPwd) PrintUsage() { func (cmd *AttachFromPwd) PrintUsage() {
...@@ -47,47 +45,23 @@ func (cmd *AttachFromPwd) Run(args []string) int { ...@@ -47,47 +45,23 @@ func (cmd *AttachFromPwd) Run(args []string) int {
return 1 return 1
} }
client := g.GetInstance().Client
host := g.GetInstance().Host
hostname := g.GetInstance().Hostname hostname := g.GetInstance().Hostname
cert := g.GetInstance().PubCert cert := g.GetInstance().PubCert
pwd := args[0] pwd := args[0]
p := &params.VMAttachCreds{Pwd: pwd} 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() { creds, err := libclient.VMGetAnySpiceCreds(p)
var creds vm.VMSpiceCredentialsSerialized if err != nil {
if err := json.Unmarshal(resp.Body(), &creds); err != nil { u.PrintlnErr(err)
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 return 1
} } else {
go func(creds vm.VMSpiceCredentialsSerialized) { go func(creds vm.VMSpiceCredentialsSerialized) {
_, err := e.RunRemoteViewer(hostname, cert, creds.Name, creds.SpicePort, creds.SpicePwd, true) _, err := e.RunRemoteViewer(hostname, cert, creds.Name, creds.SpicePort, creds.SpicePwd, true)
if err != nil { if err != nil {
u.PrintlnErr("Failed executing remote-viewer: " + err.Error()) u.PrintlnErr("Failed executing remote-viewer: " + err.Error())
} }
}(creds) }(*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 return 0
......
...@@ -41,7 +41,7 @@ func (cmd *Creds2csv) Run(args []string) int { ...@@ -41,7 +41,7 @@ func (cmd *Creds2csv) Run(args []string) int {
csvFile := args[argc-1] csvFile := args[argc-1]
credsList, err := getFilteredVMCredentials("/vms/attach", args[:argc-1]) credsList, err := getFilteredVMCredentials(args[:argc-1])
if err != nil { if err != nil {
u.PrintlnErr("Error: " + err.Error()) u.PrintlnErr("Error: " + err.Error())
return 1 return 1
......
...@@ -44,7 +44,7 @@ func (cmd *Creds2pdf) Run(args []string) int { ...@@ -44,7 +44,7 @@ func (cmd *Creds2pdf) Run(args []string) int {
pdfFile := args[argc-1] pdfFile := args[argc-1]
credsList, err := getFilteredVMCredentials("/vms/attach", args[:argc-1]) credsList, err := getFilteredVMCredentials(args[:argc-1])
if err != nil { if err != nil {
u.PrintlnErr("Error: " + err.Error()) u.PrintlnErr("Error: " + err.Error())
return 1 return 1
......
...@@ -36,7 +36,7 @@ func (cmd *ListSingle) Run(args []string) int { ...@@ -36,7 +36,7 @@ func (cmd *ListSingle) Run(args []string) int {
} }
vmID := args[0] vmID := args[0]
vm, err := libclient.GetListableVM(vmID) vm, err := libclient.GetListVM(vmID)
if err != nil { if err != nil {
u.PrintlnErr(err) u.PrintlnErr(err)
return 1 return 1
......
...@@ -73,7 +73,7 @@ func (cmd *StartAttach) Run(args []string) int { ...@@ -73,7 +73,7 @@ func (cmd *StartAttach) Run(args []string) int {
} }
// at this point, the returned filtered credentials only works for VMs that started successfully // at this point, the returned filtered credentials only works for VMs that started successfully
creds, err := getFilteredVMCredentials("/vms/attach", args) creds, err := getFilteredVMCredentials(args)
if err != nil { if err != nil {
u.PrintlnErr(err) u.PrintlnErr(err)
return 1 return 1
...@@ -84,7 +84,7 @@ func (cmd *StartAttach) Run(args []string) int { ...@@ -84,7 +84,7 @@ func (cmd *StartAttach) Run(args []string) int {
return 1 return 1
} }
attachStatusCode, err := AttachToVMs(creds, false) attachStatusCode, err := AttachToVMs(creds)
if err != nil { if err != nil {
u.PrintlnErr(err) u.PrintlnErr(err)
} }
......
...@@ -60,7 +60,7 @@ var cmdList = []cmd.Command{ ...@@ -60,7 +60,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.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"},
......
...@@ -69,31 +69,31 @@ func getFilteredVMs(route string) ([]vm.VMNetworkSerialized, error) { ...@@ -69,31 +69,31 @@ func getFilteredVMs(route string) ([]vm.VMNetworkSerialized, error) {
} }
if resp.IsSuccess() { if resp.IsSuccess() {
templates, err := deserializeVMs(resp) vms, err := deserializeVMs(resp)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return templates, nil return vms, nil
} else { } else {
return nil, response.ErrorToMsg(resp) return nil, response.ErrorToMsg(resp)
} }
} }
func GetListableVM(uuid string) (*vm.VMNetworkSerialized, error) { func GetListVM(vmID string) (*vm.VMNetworkSerialized, error) {
client := g.GetInstance().Client client := g.GetInstance().Client
host := g.GetInstance().Host host := g.GetInstance().Host
resp, err := client.R().Get(host + "/vms/" + uuid) resp, err := client.R().Get(host + "/vms/" + vmID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if resp.IsSuccess() { if resp.IsSuccess() {
template, err := deserializeVM(resp) vm, err := deserializeVM(resp)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return template, nil return vm, nil
} else { } else {
return nil, response.ErrorToMsg(resp) return nil, response.ErrorToMsg(resp)
} }
......
package vm
import (
"encoding/json"
"errors"
"nexus-common/params"
"nexus-common/vm"
g "nexus-libclient/globals"
"nexus-libclient/response"
"github.com/go-playground/validator/v10"
"github.com/go-resty/resty/v2"
)
func VMGetSpiceCreds(vmID string, p params.VMAttachCreds) (*vm.VMSpiceCredentialsSerialized, error) {
client := g.GetInstance().Client
host := g.GetInstance().Host
resp, err := client.R().SetBody(p).Post(host + "/vms/" + vmID + "/spicecreds")
if err != nil {
return nil, err
}
return handleResponse(resp)
}
func VMGetAnySpiceCreds(p params.VMAttachCreds) (*vm.VMSpiceCredentialsSerialized, error) {
client := g.GetInstance().Client
host := g.GetInstance().Host
resp, err := client.R().SetBody(p).Post(host + "/vms/spicecreds")
if err != nil {
return nil, err
}
return handleResponse(resp)
}
func handleResponse(resp *resty.Response) (*vm.VMSpiceCredentialsSerialized, error) {
if resp.IsSuccess() {
var creds vm.VMSpiceCredentialsSerialized
if err := json.Unmarshal(resp.Body(), &creds); err != nil {
return nil, errors.New("Failed deserializing VM spice credentials: " + err.Error())
}
if err := validator.New(validator.WithRequiredStructEnabled()).Struct(creds); err != nil {
return nil, errors.New("Failed validating VM spice credentials: " + err.Error())
}
return &creds, nil
} else {
return nil, response.ErrorToMsg(resp)
}
}
...@@ -205,7 +205,8 @@ func (r *RouterVMs) VMSpiceCreds(c echo.Context) error { ...@@ -205,7 +205,8 @@ 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 // Output: nexus-common/vm.VMSpiceCredentialsSerialized
// Requires either CAP_EXAM_ATTACH or CAP_VM_ATTACH_ANY user capability: // Requires either to be the VM's owner, or either capability:
// CAP_EXAM_ATTACH or 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 {
// Retrieves logged user from context. // Retrieves logged user from context.
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment