Select Git revision
vmAddAccess.go
vmAddAccess.go 6.03 KiB
package cmdVM
import (
"io"
"os"
"errors"
"strings"
"net/mail"
"encoding/csv"
u "nexus-client/utils"
g "nexus-client/globals"
)
type AddAccess struct {
Name string
}
func (cmd *AddAccess)GetName() string {
return cmd.Name
}
func (cmd *AddAccess)GetDesc() []string {
return []string{
"Adds a user's VM access in one or more VMs.",
"Requires VM_SET_ACCESS user capability and VM_SET_ACCESS VM access capability."}
}
func (cmd *AddAccess)PrintUsage() {
for _, desc := range cmd.GetDesc() {
u.PrintlnErr(desc)
}
u.PrintlnErr("―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――")
u.PrintlnErr("USAGE: "+cmd.GetName()+" [ID ...] [regex ...] email [capability ...]")
u.PrintlnErr(" "+cmd.GetName()+" file.csv")
u.PrintlnErr("―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――")
const usage string = `file.csv 3-column CSV file specifying which VMs must have which VM access added:
column1 VM ID
column2 email for which the VM Access must be removed
column3 capabilities (space separated)`
u.PrintlnErr(usage)
printRegexUsageDetails()
}
type vmAccessForUserCaps struct {
Access map[string]int `json:"access" validate:"required"`
}
func (cmd *AddAccess)Run(args []string) int {
argc := len(args)
if argc < 1 {
cmd.PrintUsage()
return 1
}
statusCode := 0
if argc == 1 {
// Single argument and it's a CSV file
csvFile := args[0]
file, err := os.Open(csvFile)
if err != nil {
u.PrintlnErr("Error: "+err.Error())
return 1
}
defer file.Close()
reader := csv.NewReader(file)
line := 0
for {
line += 1
columns, err := reader.Read()
if err == io.EOF {
break
}
if err != nil {
u.PrintlnErr("FAILED reading "+err.Error())
statusCode = 1
continue
}
columnCount := len(columns)
if columnCount != 3 {
u.PrintlnErr("FAILED reading record on line ",line,": expecting 3 columns")
statusCode = 1
continue
}
vmID := columns[0]
email := columns[1]
if !u.IsEmail(email) {
u.PrintlnErr("FAILED reading record on line ",line,": ",email," is not a valid email")
statusCode = 1
continue
}
vmAccessCaps := &vmAccessForUserCaps { make(map[string]int) }
capsStr := strings.TrimSpace(columns[2])
if len(capsStr) > 0 {
caps := strings.Split(capsStr, " ")
for _, cap := range caps {
vmAccessCaps.Access[cap] = 1
}
}
if err := cmd.runRequest(vmID, vmID, email, vmAccessCaps); err != nil {
u.PrintlnErr(err.Error())
statusCode = 1
} else {
u.Println("Successfully set VM access for "+email+" in VM \""+vmID+"\"")
}
}
} else {
// Multiple arguments: not a CSV file
email, caps, patterns, err := cmd.parseArgs(args)
if err != nil {
u.PrintlnErr(err.Error())
return 1
}
vms, err := getFilteredVMs("/vms/editaccess", patterns)
if err != nil {
u.PrintlnErr(err.Error())
return 1
}
if len(vms) == 0 {
u.PrintlnErr("Error: VM(s) not found.")
return 1
}
vmAccessCaps := &vmAccessForUserCaps { make(map[string]int) }
for _, cap := range caps {
vmAccessCaps.Access[cap] = 1
}
for _, vm := range(vms) {
vmID := vm.ID.String()
vmName := vm.Name
if err := cmd.runRequest(vmID, vmName, email, vmAccessCaps); err != nil {
u.PrintlnErr(err.Error())
statusCode = 1
} else {
u.Println("Successfully set VM access for "+email+" in VM \""+vm.Name+"\"")
}
}
}
return statusCode
}
func (cmd *AddAccess)runRequest(vmID, vmName, email string, vmAccessCaps *vmAccessForUserCaps) error {
client := g.GetInstance().Client
host := g.GetInstance().Host
resp, err := client.R().SetBody(vmAccessCaps).Put(host+"/vms/"+vmID+"/access/"+email)
if err != nil {
return errors.New("Failed setting VM access for "+email+" in VM \""+vmName+"\": "+err.Error())
}
if resp.IsSuccess() {
return nil
} else {
return errors.New("Failed setting VM access for "+email+" in VM \""+vmName+"\": "+resp.Status()+": "+resp.String())
}
}
func (cmd *AddAccess)parseArgs(args []string) (string, []string, []string, error) {
var patterns []string
var capabilities []string
emailFound := false
var email string
for _, arg := range args {
// Before or after the email addres?
if !emailFound {
// Before the email address: it's either a "pattern" (ID or regex) or an email
parsed, err := mail.ParseAddress(arg)
if err != nil {
// Not an email address, then must be a "pattern" (ID or regex)
patterns = append(patterns, arg)
} else {
email = parsed.Address
emailFound = true
}
} else {
// After the email address: it's a capability
capabilities = append(capabilities, arg)
}
}
if !emailFound {
return "", nil, nil, errors.New("An email address must be specified")
}
return email, capabilities, patterns, nil
}