diff --git a/src/client_cli/cmdTemplate/helper.go b/src/client_cli/cmdTemplate/helper.go index e6e996116ecf218a6b4e8db7194b4e43c733773e..9fbd514eaa88b4f33fd45a6ffd6120d0ff28baf7 100644 --- a/src/client_cli/cmdTemplate/helper.go +++ b/src/client_cli/cmdTemplate/helper.go @@ -44,8 +44,8 @@ Regex examples: } // Returns a list of filtered templates for a given route. -// The filter is based on the specified IDs and regexes. -// The filters argument can either be: +// Filters are based on patterns describing IDs or regexes. +// Patterns can either be: // - any number of "template IDs" (UUID) // - any number of "template names" // - any combination of "template IDs" and "template names" @@ -55,24 +55,24 @@ Regex examples: // "" -> matches everything // "." -> matches everything // "bla" -> matches any template name containing "bla" -func printFilteredTemplates(c cmd.Command, filters []string, route string) int { - client := g.GetInstance().Client - host := g.GetInstance().Host - - if len(filters) < 1 { +func printFilteredTemplates(c cmd.Command, patterns []string, route string) int { + if len(patterns) < 1 { c.PrintUsage() return 1 } + client := g.GetInstance().Client + host := g.GetInstance().Host + var ids []string var regexes []string - for _, filter := range filters { - _, err := uuid.Parse(filter) + for _, pattern := range patterns { + _, err := uuid.Parse(pattern) if err != nil { - regexes = append(regexes, filter) + regexes = append(regexes, pattern) } else { - ids = append(ids, filter) + ids = append(ids, pattern) } } diff --git a/src/client_cli/cmdUser/helper.go b/src/client_cli/cmdUser/helper.go index 001f99bafccdf4052b778569ac28b9f3c79217f7..332c283f26fd9c4ad2e36a5590fd09094f3767db 100644 --- a/src/client_cli/cmdUser/helper.go +++ b/src/client_cli/cmdUser/helper.go @@ -53,14 +53,14 @@ Regex examples: // "." -> matches everything // "bla" -> matches any user containing "bla" func printFilteredUsers(c cmd.Command, regexes []string, route string) int { - client := g.GetInstance().Client - host := g.GetInstance().Host - if len(regexes) < 1 { c.PrintUsage() return 1 } + client := g.GetInstance().Client + host := g.GetInstance().Host + resp, err := client.R().Get(host+route) if err != nil { u.PrintlnErr("Error: "+err.Error()) diff --git a/src/client_cli/cmdVM/helper.go b/src/client_cli/cmdVM/helper.go index 5e33c496c6c144673cf6a5e9fe71de19474124c4..83baf9b6dbdab7c4da5951d97dcd2df75c39323d 100644 --- a/src/client_cli/cmdVM/helper.go +++ b/src/client_cli/cmdVM/helper.go @@ -87,8 +87,8 @@ func printFilteredVMs(c cmd.Command, args []string, route string) int { } // Returns a list of filtered VMs for a given route. -// The filter is based on the specified IDs and regexes. -// The filters argument can either be: +// Filters are based on patterns describing IDs or regexes. +// Patterns can either be: // - any number of "VM IDs" (UUID) // - any number of "VM names" // - any combination of "VM IDs" and "VM names" @@ -98,26 +98,28 @@ func printFilteredVMs(c cmd.Command, args []string, route string) int { // "" -> matches everything // "." -> matches everything // "bla" -> matches any VM name containing "bla" -func getFilteredVMs(route string, filters []string) ([]VM, error) { +func getFilteredVMs(route string, patterns []string) ([]VM, error) { + if len(patterns) < 1 { + return nil, errors.New("At least one ID or regex must be specified") + } + client := g.GetInstance().Client host := g.GetInstance().Host var ids []string var regexes []string - for _, filter := range filters { - _, err := uuid.Parse(filter) + for _, pattern := range patterns { + _, err := uuid.Parse(pattern) if err != nil { - regexes = append(regexes, filter) + regexes = append(regexes, pattern) } else { - ids = append(ids, filter) + ids = append(ids, pattern) } } resp, err := client.R().Get(host+route) if err != nil { - //u.PrintlnErr("Error: "+err.Error()) - //return 1 return nil, err } @@ -126,8 +128,6 @@ func getFilteredVMs(route string, filters []string) ([]VM, error) { if resp.IsSuccess() { vms, err := getVMs(resp) if err != nil { - //u.PrintlnErr("Error: "+err.Error()) - //return 1 return nil, err } @@ -136,7 +136,6 @@ func getFilteredVMs(route string, filters []string) ([]VM, error) { for _, id := range ids { if id == vm.ID.String() { vmsList = append(vmsList, vm) - //u.Println(vm.String()) found = true break } @@ -147,11 +146,9 @@ func getFilteredVMs(route string, filters []string) ([]VM, error) { for _, regex := range regexes { match, err := regexp.MatchString(strings.ToLower(regex), strings.ToLower(vm.Name)) if err != nil { - //u.PrintlnErr("Error matching \""+regex+"\": "+err.Error()) return nil, errors.New("Error matching \""+regex+"\": "+err.Error()) } else { if match { - //u.Println(vm.String()) vmsList = append(vmsList, vm) break } @@ -161,8 +158,6 @@ func getFilteredVMs(route string, filters []string) ([]VM, error) { return vmsList, nil } else { return nil, errors.New("Error: "+resp.Status()+": "+resp.String()) - //u.PrintlnErr("Error: "+resp.Status()+": "+resp.String()) - //return 1 } } diff --git a/src/client_cli/cmdVM/vmDelAccess.go b/src/client_cli/cmdVM/vmDelAccess.go index dc09edab8513bcf977d0e8b600335c4a438ca8f6..30398e25e8ab4e9af424bcc0012b326ff4e5637b 100644 --- a/src/client_cli/cmdVM/vmDelAccess.go +++ b/src/client_cli/cmdVM/vmDelAccess.go @@ -1,6 +1,8 @@ package cmdVM import ( + "errors" + "net/mail" u "nexus-client/utils" g "nexus-client/globals" ) @@ -9,17 +11,29 @@ type DelAccess struct { Name string } +type vmDelAccessParameters struct { + +} + func (cmd *DelAccess)GetName() string { return cmd.Name } func (cmd *DelAccess)GetDesc() string { - return "Delete the VM access for a given user." + return "Delete a user's VM access in one or more VMs (regex matching)." } func (cmd *DelAccess)PrintUsage() { u.PrintlnErr(cmd.GetDesc()) - u.PrintlnErr("Usage: "+cmd.Name+" vmID email") + u.PrintlnErr("Usage: "+cmd.GetName()+" [ID ...] [regex ...] email") + const usage string = `Only VMs matching the specified IDs or regexes will have their VM access deleted. +Any number of IDs or regexes can be specified. +The regex only matches the VM's name and is case-insensitive. +Regex examples: +"" -> matches any VMs +"." -> matches any VMs +"bla" -> matches any VMs containing "bla" in their name` + u.PrintlnErr(usage) } func (cmd *DelAccess)Run(args []string) int { @@ -27,25 +41,67 @@ func (cmd *DelAccess)Run(args []string) int { host := g.GetInstance().Host argc := len(args) - if argc != 2 { + if argc < 1 { cmd.PrintUsage() return 1 } - vmID := args[0] - email := args[1] - - resp, err := client.R().Delete(host+"/vms/"+vmID+"/access/"+email) + email, patterns, err := cmd.parseArgs(args) if err != nil { - u.PrintlnErr("Error: "+err.Error()) + u.PrintlnErr(err.Error()) return 1 } - if resp.IsSuccess() { - u.Println(resp) - return 0 - } else { - u.PrintlnErr("Error: "+resp.Status()+": "+resp.String()) + vms, err := getFilteredVMs("/vms/editaccess", patterns) + if err != nil { + u.PrintlnErr(err.Error()) return 1 } + + statusCode := 0 + + for _, vm := range(vms) { + uuid := vm.ID.String() + resp, err := client.R().Delete(host+"/vms/"+uuid+"/access/"+email) + if err != nil { + u.PrintlnErr("Failed removing VM access for "+email+" in VM \""+vm.Name+"\" ("+uuid+"): "+err.Error()) + statusCode = 1 + } else { + if resp.IsSuccess() { + u.Println("Removed VM access for "+email+" in VM \""+vm.Name+"\" ("+uuid+")") + } else { + u.PrintlnErr("Failed removing VM access for "+email+" in VM \""+vm.Name+"\" ("+uuid+"): "+resp.Status()+": "+resp.String()) + statusCode = 1 + } + } + } + + return statusCode +} + +func (cmd *DelAccess)parseArgs(args []string) (string, []string, error) { + var patterns []string + emailFound := false + var email string + + for _, arg := range args { + 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 { + // An email address was found + if emailFound { + return "", nil, errors.New("Only one email address must be specified") + } + email = parsed.Address + emailFound = true + } + } + + if !emailFound { + return "", nil, errors.New("An email address must be specified") + } + + return email, patterns, nil } diff --git a/src/client_cli/cmdVM/vmEdit.go b/src/client_cli/cmdVM/vmEdit.go index c96c178ff5f79877cec4a96c2e9efb6fef85e5f4..c00d85e92cf1ca54aa7c9897d20d72d676f82b45 100644 --- a/src/client_cli/cmdVM/vmEdit.go +++ b/src/client_cli/cmdVM/vmEdit.go @@ -30,8 +30,8 @@ func (cmd *Edit)GetDesc() string { func (cmd *Edit)PrintUsage() { u.PrintlnErr(cmd.GetDesc()) u.PrintlnErr("Usage: "+cmd.GetName()+" [ID ...] [regex ...] [name=\"new name\"] [cpus=n] [ram=n] [nic=none/user]") - u.PrintlnErr("Only VMs matching the specified IDs or regexes will be edited.") - const usage string = `Any number of IDs or regexes can be specified. + const usage string = `Only VMs matching the specified IDs or regexes will be edited. +Any number of IDs or regexes can be specified. The regex only matches the VM's name and is case-insensitive. Regex examples: "" -> matches any VMs @@ -44,17 +44,57 @@ nic must be either "none" or "user` u.PrintlnErr(usage) } -func (cmd *Edit)getStringVal(s string, prefix string) string { - if strings.HasPrefix(s, prefix) { - parts := strings.Split(s, prefix) - return parts[1] +func (cmd *Edit)Run(args []string) int { + client := g.GetInstance().Client + host := g.GetInstance().Host + + argc := len(args) + if argc < 1 { + cmd.PrintUsage() + return 1 } - return "" + + vmParams, patterns, err := cmd.parseArgs(args) + if err != nil { + u.PrintlnErr(err.Error()) + return 1 + } + + if vmParams == nil { + cmd.PrintUsage() + return 1 + } + + vms, err := getFilteredVMs("/vms/edit", patterns) + if err != nil { + u.PrintlnErr(err.Error()) + return 1 + } + + statusCode := 0 + + for _, vm := range(vms) { + uuid := vm.ID.String() + resp, err := client.R().SetBody(vmParams).Put(host+"/vms/"+uuid) + if err != nil { + u.PrintlnErr("Failed editing VM \""+vm.Name+"\" ("+uuid+"): "+err.Error()) + statusCode = 1 + } else { + if resp.IsSuccess() { + u.Println("Edited VM \""+vm.Name+"\" ("+uuid+")") + } else { + u.PrintlnErr("Failed editing VM \""+vm.Name+"\" ("+uuid+"): "+resp.Status()+": "+resp.String()) + statusCode = 1 + } + } + } + + return statusCode } func (cmd *Edit)parseArgs(args []string) (*vmEditParameters, []string, error) { vmParams := &vmEditParameters {} - var regex []string + var patterns []string atLeastOneArg := false for _, arg := range args { @@ -91,61 +131,20 @@ func (cmd *Edit)parseArgs(args []string) (*vmEditParameters, []string, error) { continue } - regex = append(regex, arg) + patterns = append(patterns, arg) } if atLeastOneArg { - return vmParams, regex, nil + return vmParams, patterns, nil } else { return nil, nil, nil } } -func (cmd *Edit)Run(args []string) int { - client := g.GetInstance().Client - host := g.GetInstance().Host - - argc := len(args) - if argc < 1 { - cmd.PrintUsage() - return 1 - } - - vmParams, regex, err := cmd.parseArgs(args) - if err != nil { - u.PrintlnErr(err.Error()) - return 1 - } - - if vmParams == nil { - cmd.PrintUsage() - return 1 - } - - vms, err := getFilteredVMs("/vms/edit", regex) - if err != nil { - u.PrintlnErr(err.Error()) - return 1 - } - - statusCode := 0 - - for _, vm := range(vms) { - uuid := vm.ID.String() - resp, err := client.R().SetBody(vmParams).Put(host+"/vms/"+uuid) - if err != nil { - u.PrintlnErr("Failed editing VM \""+vm.Name+"\" ("+uuid+"): "+err.Error()) - statusCode = 1 - } else { - if resp.IsSuccess() { - u.Println("Edited VM \""+vm.Name+"\" ("+uuid+")") - } else { - u.PrintlnErr("Failed editing VM \""+vm.Name+"\" ("+uuid+"): "+resp.Status()+": "+resp.String()) - statusCode = 1 - } - } - +func (cmd *Edit)getStringVal(s string, prefix string) string { + if strings.HasPrefix(s, prefix) { + parts := strings.Split(s, prefix) + return parts[1] } - - return statusCode + return "" } diff --git a/src/client_cli/cmdVM/vmSetAccess.go b/src/client_cli/cmdVM/vmSetAccess.go index c8ce79531347583b192e1a8e0975b1f6f8a164c5..5d8ba08483c66cc5819ebc02a3287509dd390ea5 100644 --- a/src/client_cli/cmdVM/vmSetAccess.go +++ b/src/client_cli/cmdVM/vmSetAccess.go @@ -1,6 +1,8 @@ package cmdVM import ( + "errors" + "net/mail" u "nexus-client/utils" g "nexus-client/globals" ) @@ -14,12 +16,21 @@ func (cmd *SetAccess)GetName() string { } func (cmd *SetAccess)GetDesc() string { - return "Set the VM access for a given user." + return "Set a user's VM access in one or more VMs (regex matching)." } func (cmd *SetAccess)PrintUsage() { u.PrintlnErr(cmd.GetDesc()) - u.PrintlnErr("Usage: "+cmd.Name+" vmID email [capability ...]") + u.PrintlnErr("Usage: "+cmd.GetName()+" [ID ...] [regex ...] email [capability ...]") + const usage string = `Capabilities must be specified after the email. +Only VMs matching the specified IDs or regexes will have their VM access set. +Any number of IDs or regexes can be specified. +The regex only matches the VM's name and is case-insensitive. +Regex examples: +"" -> matches any VMs +"." -> matches any VMs +"bla" -> matches any VMs containing "bla" in their name` + u.PrintlnErr(usage) } func (cmd *SetAccess)Run(args []string) int { @@ -27,34 +38,80 @@ func (cmd *SetAccess)Run(args []string) int { host := g.GetInstance().Host argc := len(args) - if argc < 2 { + if argc < 1 { cmd.PrintUsage() return 1 } - vmID := args[0] - email := args[1] + email, caps, patterns, err := cmd.parseArgs(args) + if err != nil { + u.PrintlnErr(err.Error()) + return 1 + } - type VMAccessForUserArgs struct { + vms, err := getFilteredVMs("/vms/editaccess", patterns) + if err != nil { + u.PrintlnErr(err.Error()) + return 1 + } + + type vmAccessForUserArgs struct { Access map[string]int `json:"access" validate:"required"` } - - userUpdatedAccessArgs := &VMAccessForUserArgs { make(map[string]int) } - for _, cap := range args[2:] { + + userUpdatedAccessArgs := &vmAccessForUserArgs { make(map[string]int) } + for _, cap := range caps { userUpdatedAccessArgs.Access[cap] = 1 } - resp, err := client.R().SetBody(userUpdatedAccessArgs).Put(host+"/vms/"+vmID+"/access/"+email) - if err != nil { - u.PrintlnErr("Error: "+err.Error()) - return 1 + statusCode := 0 + + for _, vm := range(vms) { + uuid := vm.ID.String() + resp, err := client.R().SetBody(userUpdatedAccessArgs).Put(host+"/vms/"+uuid+"/access/"+email) + if err != nil { + u.PrintlnErr("Failed removing VM access for "+email+" in VM \""+vm.Name+"\" ("+uuid+"): "+err.Error()) + statusCode = 1 + } else { + if resp.IsSuccess() { + u.Println("Removed VM access for "+email+" in VM \""+vm.Name+"\" ("+uuid+")") + } else { + u.PrintlnErr("Failed removing VM access for "+email+" in VM \""+vm.Name+"\" ("+uuid+"): "+resp.Status()+": "+resp.String()) + statusCode = 1 + } + } } - if resp.IsSuccess() { - u.Println(resp) - return 0 - } else { - u.PrintlnErr("Error: "+resp.Status()+": "+resp.String()) - return 1 + return statusCode +} + +func (cmd *SetAccess)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 }