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

Added new command:

---------------------
vmstartwithcreds    Starts one or more VMs with user-defined credentials.
                    Requires VM_START VM access capability or VM_START_ANY user capability.
---------------------
client: fixed ReadCSVColumn which didn't work if separator char was not a comma
parent e2ae4057
Branches
No related tags found
No related merge requests found
......@@ -140,6 +140,14 @@ nexush> help
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
ls List files in the specified dir or in the current dir if no argument is specified.
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
refresh Obtains a new access token.
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
version Display nexus server and client's versions.
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
whoami Displays the current user's details.
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
passwd Updates the current user's password.
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
userlist Lists users.
Requires USER_LIST user capability.
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
......@@ -158,12 +166,16 @@ vmlist Lists VMs.
vmcred2pdf Creates a PDF with the credentials required to attach to running VMs.
Requires VM_LIST VM access capability or VM_LIST_ANY user capability.
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
vmcred2txt Creates a text file with the credentials required to attach to running VMs.
vmcred2csv Creates a CSV file with the credentials required to attach to running VMs.
The written CSV file contains 4 columns: VM ID;VM name;port;password
Requires VM_LIST VM access capability or VM_LIST_ANY user capability.
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
vmstart Starts one or more VMs.
Requires VM_START VM access capability or VM_START_ANY user capability.
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
vmstartwithcreds Starts one or more VMs with user-defined credentials.
Requires VM_START VM access capability or VM_START_ANY user capability.
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
vmkill Kills one or more VMs.
Requires VM_STOP VM access capability or VM_STOP_ANY user capability.
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
......@@ -191,13 +203,13 @@ vmaddaccess Adds a user's VM access in one or more VMs.
vmdelaccess Removes a user's VM access in one or more VMs.
Requires VM_SET_ACCESS user capability and VM_SET_ACCESS VM access capability.
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
vmexportdir Exports one or more VMs' directory into one or more tar archives.
vmexportdir Exports one or more VMs' directory into one or more compressed archives.
Requires VM_READFS VM access capability or VM_READFS_ANY user capability.
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
vmimportdir Copies a local directory (or file) and all its content into one or more VMs.
Requires VM_WRITEFS VM access capability or VM_WRITEFS_ANY user capability.
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
tpllist Lists available templates.
tpllist Lists templates.
Requires TPL_LIST or TPL_LIST_ANY user capability.
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
tplcreate Creates a template from an existing VM.
......
package cmdVM
import (
"errors"
"strconv"
u "nexus-client/utils"
g "nexus-client/globals"
)
type StartWithCreds struct {
Name string
}
func (cmd *StartWithCreds)GetName() string {
return cmd.Name
}
func (cmd *StartWithCreds)GetDesc() []string {
return []string{
"Starts one or more VMs with user-defined credentials.",
"Requires VM_START VM access capability or VM_START_ANY user capability."}
}
func (cmd *StartWithCreds)PrintUsage() {
for _, desc := range cmd.GetDesc() {
u.PrintlnErr(desc)
}
u.PrintlnErr("―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――")
u.PrintlnErr("USAGE: "+cmd.GetName()+" file.csv")
u.PrintlnErr("―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――")
const usage string = `file.csv 4-column CSV file defining the VMs to start and their credentials.
Content of the 4 columns: VM ID;VM name;port;password.`
u.PrintlnErr(usage)
}
func (cmd *StartWithCreds)parseCSVFile(csvFile string) ([]string, []string, []string, error) {
// Column 0: VM IDs
vmIDs, err := u.ReadCSVColumn(csvFile, 0)
if err != nil {
return nil, nil, nil, err
}
// Column 2: ports
ports, err := u.ReadCSVColumn(csvFile, 2)
if err != nil {
return nil, nil, nil, err
}
// Column 3: passwords
pwds, err := u.ReadCSVColumn(csvFile, 3)
if err != nil {
return nil, nil, nil, err
}
count := len(vmIDs)
if (len(ports) != count) || (len(pwds) != count) {
return nil, nil, nil, errors.New("Invalid CSV file: all columns must have the same number of entries!")
}
return vmIDs, ports, pwds, nil
}
func (cmd *StartWithCreds)Run(args []string) int {
client := g.GetInstance().Client
host := g.GetInstance().Host
argc := len(args)
if argc != 1 {
cmd.PrintUsage()
return 1
}
vmIDs, ports, pwds, err := cmd.parseCSVFile(args[0])
if err != nil {
u.PrintlnErr(err.Error())
return 1
}
statusCode := 0
type VMArgs struct {
Port int
Pwd string
}
vmArgs := &VMArgs {}
for i, vmID := range(vmIDs) {
port, err := strconv.Atoi(ports[i])
if err != nil {
u.PrintlnErr("Line ",i,": invalid port number")
}
vmArgs.Port = port
vmArgs.Pwd = pwds[i]
resp, err := client.R().SetBody(vmArgs).Put(host+"/vms/"+vmID+"/startwithcreds")
if err != nil {
u.PrintlnErr("Failed starting VM \""+vmID+"\": "+err.Error())
statusCode = 1
} else {
if resp.IsSuccess() {
u.Println("Started VM \""+vmID+"\"")
} else {
u.PrintlnErr("Failed starting VM \""+vmID+"\": "+resp.Status()+": "+resp.String())
statusCode = 1
}
}
}
return statusCode
}
......@@ -38,6 +38,7 @@ var cmdList = []cmd.Command {
&cmdVM.Cred2pdf{"vmcred2pdf"},
&cmdVM.Cred2csv{"vmcred2csv"},
&cmdVM.Start{"vmstart"},
&cmdVM.StartWithCreds{"vmstartwithcreds"},
&cmdVM.Stop{"vmkill"},
&cmdVM.Shutdown{"vmshutdown"},
&cmdVM.Reboot{"vmreboot"},
......
......@@ -45,6 +45,7 @@ var cmdList = []cmd.Command {
&cmdVM.Cred2pdf{"vmcred2pdf"},
&cmdVM.Cred2csv{"vmcred2csv"},
&cmdVM.Start{"vmstart"},
&cmdVM.StartWithCreds{"vmstartwithcreds"},
&cmdVM.Stop{"vmkill"},
&cmdVM.Shutdown{"vmshutdown"},
&cmdVM.Reboot{"vmreboot"},
......
......@@ -4,6 +4,7 @@ import (
"os"
"io"
"errors"
"strconv"
"encoding/csv"
)
......@@ -16,6 +17,8 @@ func ReadCSVColumn(csvFile string, column int) ([]string, error) {
}
defer file.Close()
reader := csv.NewReader(file)
reader.Comma = ';' // specify the column separator
reader.Comment = '#' // lines starting with this symbol are to be ignored
var entries []string
for {
......@@ -26,8 +29,9 @@ func ReadCSVColumn(csvFile string, column int) ([]string, error) {
if err != nil {
return nil, errors.New("Failed reading "+err.Error())
}
if column >= len(record) {
return nil, errors.New("Failed reading \""+csvFile+"\": column out of bound")
colCount := len(record)
if column >= colCount {
return nil, errors.New("Failed reading \""+csvFile+"\": column out of bound (detected "+strconv.Itoa(colCount)+" columns)")
}
entries = append(entries, record[column])
}
......
......@@ -244,16 +244,15 @@ func (r *RouterVMs)StartVMWithCreds(c echo.Context) 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"`
Port int `json:"port" validate:"required,gte=1100,lte=65535"`
Pwd string `json:"pwd" validate:"required,min=8,max=64"`
}
p := new(Parameters)
if err := decodeJson(c, &p); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, err.Error())
}
_, _, err := r.vms.StartVM(vm.GetID())
if err != nil {
if err := r.vms.StartVMWithCreds(vm.GetID(), p.Port, p.Pwd); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, err.Error())
}
return c.JSONPretty(http.StatusOK, jsonMsg("OK"), " ")
......
......@@ -177,6 +177,12 @@ func (vms *VMs)StartVMWithCreds(vmID uuid.UUID, port int, 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
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment