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

Users and templates can be filtered using a regex similarly to what's possible with VMs

parent f1bf9b59
No related branches found
No related tags found
No related merge requests found
Showing with 253 additions and 92 deletions
package cmdTemplate
import (
"strings"
"regexp"
"encoding/json"
"nexus-client/cmd"
u "nexus-client/utils"
g "nexus-client/globals"
"github.com/google/uuid"
"github.com/go-resty/resty/v2"
)
// Make sure these types MATCH their counterparts in nexus-server codebase!
type (
Template struct {
ID uuid.UUID `json:"id" validate:"required"`
Name string `json:"name" validate:"required,min=2,max=256"`
Owner string `json:"owner" validate:"required,email"`
Access string `json:"access" validate:"required,min=4,max=16"` // private or public
}
)
// Converts a Template structure into a pretty string.
func (tpl *Template)String() string {
output, err := json.MarshalIndent(tpl, "", " ")
if err != nil {
return err.Error()
}
return string(output)
}
func printUsage(c cmd.Command) {
u.PrintlnErr(c.GetDesc())
u.PrintlnErr("Usage: ",c.GetName()," [ID] [regex]")
u.PrintlnErr("Only templates matching either the specified ID or regex will be listed.")
u.PrintlnErr("Any number of ID or regex can be specified.")
u.PrintlnErr("The regex matches the template's name only and is case-insensitive.")
u.PrintlnErr("Regex examples:")
u.PrintlnErr(" \"\" -> matches any name")
u.PrintlnErr(" \".\" -> matches any name")
u.PrintlnErr(" \"bla\" -> matches any name containing \"bla\"")
}
// Call the given route and filter the results based on ID and regex.
// Arguments (args) can either be:
// - any number of "template IDs" (UUID)
// - any number of "template names"
// - any combination of "template IDs" and "template names"
// - any regular expression (it applies to the template's name only)
// Remark: the matching is case-insensitive
// Regular expression examples:
// "" -> matches everything
// "." -> matches everything
// "bla" -> matches any template name containing "bla"
func getFilteredTemplates(c cmd.Command, args []string, route string) int {
client := g.GetInstance().Client
host := g.GetInstance().Host
argc := len(args)
if argc < 1 {
c.PrintUsage()
return 1
}
var ids []string
var namePatterns []string
for _, arg := range args {
_, err := uuid.Parse(arg)
if err != nil {
namePatterns = append(namePatterns, arg)
} else {
ids = append(ids, arg)
}
}
resp, err := client.R().Get(host+route)
if err != nil {
u.PrintlnErr("Error: "+err.Error())
return 1
}
if resp.IsSuccess() {
templates, err := getTemplates(resp)
if err != nil {
u.PrintlnErr("Error: "+err.Error())
return 1
}
for _, template := range *templates {
found := false
for _, id := range ids {
if id == template.ID.String() {
u.Println(template.String())
found = true
break
}
}
if found {
continue
}
for _, namePattern := range namePatterns {
match, err := regexp.MatchString(strings.ToLower(namePattern), strings.ToLower(template.Name))
if err != nil {
u.PrintlnErr("Error matching \""+namePattern+"\": "+err.Error())
} else {
if match {
u.Println(template.String())
break
}
}
}
}
return 0
} else {
u.PrintlnErr("Error: "+resp.Status()+": "+resp.String())
return 1
}
}
func getTemplates(resp *resty.Response) (*[]Template, error) {
var templates []Template
if err := json.Unmarshal(resp.Body(), &templates); err != nil {
return nil, err
}
return &templates, nil
}
\ No newline at end of file
package cmdTemplate package cmdTemplate
import (
u "nexus-client/utils"
g "nexus-client/globals"
)
type List struct { type List struct {
Name string Name string
} }
...@@ -14,43 +9,13 @@ func (cmd *List)GetName() string { ...@@ -14,43 +9,13 @@ func (cmd *List)GetName() string {
} }
func (cmd *List)GetDesc() string { func (cmd *List)GetDesc() string {
return "List one or more templates" return "List templates that can be listed by the user"
} }
func (cmd *List)PrintUsage() { func (cmd *List)PrintUsage() {
u.PrintlnErr(cmd.GetDesc()) printUsage(cmd)
u.PrintlnErr("Usage: "+cmd.Name+" [id]")
} }
func (cmd *List)Run(args []string) int { func (cmd *List)Run(args []string) int {
client := g.GetInstance().Client return getFilteredTemplates(cmd, args, "/templates")
host := g.GetInstance().Host
argc := len(args)
if !(argc == 0 || argc == 1) {
cmd.PrintUsage()
return 1
}
var url string
if argc == 0 {
url = host+"/templates"
} else {
id := args[0]
url = host+"/templates/"+id
}
resp, err := client.R().Get(url)
if err != nil {
u.PrintlnErr("Error: "+err.Error())
return 1
}
if resp.IsSuccess() {
u.Println(resp)
return 0
} else {
u.PrintlnErr("Error: "+resp.Status()+": "+resp.String())
return 1
}
} }
package cmdUser
import (
"strings"
"regexp"
"encoding/json"
"nexus-client/cmd"
u "nexus-client/utils"
g "nexus-client/globals"
"github.com/go-resty/resty/v2"
)
// Make sure these types MATCH their counterparts in nexus-server codebase!
type (
Capabilities map[string]int
User struct {
Email string `json:"email" validate:"required,email"`
FirstName string `json:"firstname" validate:"required,min=2,max=32"`
LastName string `json:"lastname" validate:"required,min=2,max=32"`
Pwd string `json:"pwd" validate:"required,min=8"`
Caps Capabilities `json:"caps" validate:"required"`
}
)
// Converts a User structure into a pretty string.
func (user *User)String() string {
output, err := json.MarshalIndent(user, "", " ")
if err != nil {
return err.Error()
}
return string(output)
}
func printUsage(c cmd.Command) {
u.PrintlnErr(c.GetDesc())
u.PrintlnErr("Usage: ",c.GetName()," [regex]")
u.PrintlnErr("Only users matching the specified regex will be listed.")
u.PrintlnErr("Any number of regex can be specified.")
u.PrintlnErr("The regex matches the user email, first name and last name and is case-insensitive.")
u.PrintlnErr("Regex examples:")
u.PrintlnErr(" \"\" -> matches any user")
u.PrintlnErr(" \".\" -> matches any user")
u.PrintlnErr(" \"bla\" -> matches any user containing \"bla\"")
}
// Call the given route and filter the results based on a regex.
// Remark: the regex matches the user email, first name and last name and is case-insensitive.
// Regular expression examples:
// "" -> matches everything
// "." -> matches everything
// "bla" -> matches any user containing "bla"
func getFilteredUsers(c cmd.Command, args []string, route string) int {
client := g.GetInstance().Client
host := g.GetInstance().Host
argc := len(args)
if argc < 1 {
c.PrintUsage()
return 1
}
resp, err := client.R().Get(host+route)
if err != nil {
u.PrintlnErr("Error: "+err.Error())
return 1
}
if resp.IsSuccess() {
users, err := getUsers(resp)
if err != nil {
u.PrintlnErr("Error: "+err.Error())
return 1
}
for _, user := range *users {
for _, pattern := range args {
fieldsToMatch := user.Email+" "+user.FirstName+" "+user.LastName
match, err := regexp.MatchString(strings.ToLower(pattern), strings.ToLower(fieldsToMatch))
if err != nil {
u.PrintlnErr("Error matching \""+pattern+"\": "+err.Error())
} else {
if match {
u.Println(user.String())
break
}
}
}
}
return 0
} else {
u.PrintlnErr("Error: "+resp.Status()+": "+resp.String())
return 1
}
}
func getUsers(resp *resty.Response) (*[]User, error) {
var users []User
if err := json.Unmarshal(resp.Body(), &users); err != nil {
return nil, err
}
return &users, nil
}
\ No newline at end of file
package cmdUser package cmdUser
import (
u "nexus-client/utils"
g "nexus-client/globals"
)
type List struct { type List struct {
Name string Name string
} }
...@@ -14,43 +9,13 @@ func (cmd *List)GetName() string { ...@@ -14,43 +9,13 @@ func (cmd *List)GetName() string {
} }
func (cmd *List)GetDesc() string { func (cmd *List)GetDesc() string {
return "List one or all users" return "List users"
} }
func (cmd *List)PrintUsage() { func (cmd *List)PrintUsage() {
u.PrintlnErr(cmd.GetDesc()) printUsage(cmd)
u.PrintlnErr("Usage: "+cmd.Name+" [email]")
} }
func (cmd *List)Run(args []string) int { func (cmd *List)Run(args []string) int {
client := g.GetInstance().Client return getFilteredUsers(cmd, args, "/users")
host := g.GetInstance().Host
argc := len(args)
if !(argc == 0 || argc == 1) {
cmd.PrintUsage()
return 1
}
var url string
if argc == 0 {
url = host+"/users"
} else {
email := args[0]
url = host+"/users/"+email
}
resp, err := client.R().Get(url)
if err != nil {
u.PrintlnErr("Error: "+err.Error())
return 1
}
if resp.IsSuccess() {
u.Println(resp)
return 0
} else {
u.PrintlnErr("Error: "+resp.Status()+": "+resp.String())
return 1
}
} }
...@@ -14,7 +14,7 @@ func (cmd *Whoami)GetName() string { ...@@ -14,7 +14,7 @@ func (cmd *Whoami)GetName() string {
} }
func (cmd *Whoami)GetDesc() string { func (cmd *Whoami)GetDesc() string {
return "Display the currently authenticated user's details" return "Display the user's details"
} }
func (cmd *Whoami)PrintUsage() { func (cmd *Whoami)PrintUsage() {
......
...@@ -53,9 +53,9 @@ func (vm *VM)String() string { ...@@ -53,9 +53,9 @@ func (vm *VM)String() string {
func printUsage(c cmd.Command) { func printUsage(c cmd.Command) {
u.PrintlnErr(c.GetDesc()) u.PrintlnErr(c.GetDesc())
u.PrintlnErr("Usage: ",c.GetName()," [vmID] [regex]") u.PrintlnErr("Usage: ",c.GetName()," [ID] [regex]")
u.PrintlnErr("Only VMs matching either the specified vmID or regex will be listed.") u.PrintlnErr("Only VMs matching either the specified ID or regex will be listed.")
u.PrintlnErr("Any number of vmID or regex can be specified.") u.PrintlnErr("Any number of ID or regex can be specified.")
u.PrintlnErr("The regex matches the VM's name only and is case-insensitive.") u.PrintlnErr("The regex matches the VM's name only and is case-insensitive.")
u.PrintlnErr("Regex examples:") u.PrintlnErr("Regex examples:")
u.PrintlnErr(" \"\" -> matches any name") u.PrintlnErr(" \"\" -> matches any name")
...@@ -63,7 +63,7 @@ func printUsage(c cmd.Command) { ...@@ -63,7 +63,7 @@ func printUsage(c cmd.Command) {
u.PrintlnErr(" \"bla\" -> matches any name containing \"bla\"") u.PrintlnErr(" \"bla\" -> matches any name containing \"bla\"")
} }
// Call the given route and filter the results based on vmID and regex. // Call the given route and filter the results based on ID and regex.
// Arguments (args) can either be: // Arguments (args) can either be:
// - any number of "VM IDs" (UUID) // - any number of "VM IDs" (UUID)
// - any number of "VM names" // - any number of "VM names"
......
...@@ -9,7 +9,7 @@ func (cmd *List)GetName() string { ...@@ -9,7 +9,7 @@ func (cmd *List)GetName() string {
} }
func (cmd *List)GetDesc() string { func (cmd *List)GetDesc() string {
return "List all VMs that can be listed" return "List VMs that can be listed by the user"
} }
func (cmd *List)PrintUsage() { func (cmd *List)PrintUsage() {
...@@ -17,5 +17,5 @@ func (cmd *List)PrintUsage() { ...@@ -17,5 +17,5 @@ func (cmd *List)PrintUsage() {
} }
func (cmd *List)Run(args []string) int { func (cmd *List)Run(args []string) int {
return getFilteredVMs(cmd, args, "/vms/list") return getFilteredVMs(cmd, args, "/vms")
} }
...@@ -9,7 +9,7 @@ func (cmd *ListAttach)GetName() string { ...@@ -9,7 +9,7 @@ func (cmd *ListAttach)GetName() string {
} }
func (cmd *ListAttach)GetDesc() string { func (cmd *ListAttach)GetDesc() string {
return "List VMs that can be attached to" return "List VMs the user can attach to"
} }
func (cmd *ListAttach)PrintUsage() { func (cmd *ListAttach)PrintUsage() {
......
...@@ -9,7 +9,7 @@ func (cmd *ListDel)GetName() string { ...@@ -9,7 +9,7 @@ func (cmd *ListDel)GetName() string {
} }
func (cmd *ListDel)GetDesc() string { func (cmd *ListDel)GetDesc() string {
return "List VMs that can be deleted" return "List VMs the user can delete"
} }
func (cmd *ListDel)PrintUsage() { func (cmd *ListDel)PrintUsage() {
......
...@@ -9,7 +9,7 @@ func (cmd *ListEdit)GetName() string { ...@@ -9,7 +9,7 @@ func (cmd *ListEdit)GetName() string {
} }
func (cmd *ListEdit)GetDesc() string { func (cmd *ListEdit)GetDesc() string {
return "List VMs that can be edited" return "List VMs the user can edit"
} }
func (cmd *ListEdit)PrintUsage() { func (cmd *ListEdit)PrintUsage() {
......
...@@ -9,7 +9,7 @@ func (cmd *ListEditAccess)GetName() string { ...@@ -9,7 +9,7 @@ func (cmd *ListEditAccess)GetName() string {
} }
func (cmd *ListEditAccess)GetDesc() string { func (cmd *ListEditAccess)GetDesc() string {
return "List VMs that can have their VM access edited" return "List VMs the user can edit the VM access for"
} }
func (cmd *ListEditAccess)PrintUsage() { func (cmd *ListEditAccess)PrintUsage() {
......
...@@ -9,7 +9,7 @@ func (cmd *ListStart)GetName() string { ...@@ -9,7 +9,7 @@ func (cmd *ListStart)GetName() string {
} }
func (cmd *ListStart)GetDesc() string { func (cmd *ListStart)GetDesc() string {
return "List VMs that can be started" return "List VMs the user can start"
} }
func (cmd *ListStart)PrintUsage() { func (cmd *ListStart)PrintUsage() {
......
...@@ -9,7 +9,7 @@ func (cmd *ListStop)GetName() string { ...@@ -9,7 +9,7 @@ func (cmd *ListStop)GetName() string {
} }
func (cmd *ListStop)GetDesc() string { func (cmd *ListStop)GetDesc() string {
return "List VMs that can be stopped" return "List VMs the user can stop"
} }
func (cmd *ListStop)PrintUsage() { func (cmd *ListStop)PrintUsage() {
......
...@@ -5,8 +5,8 @@ import ( ...@@ -5,8 +5,8 @@ import (
) )
type Globals struct { type Globals struct {
Host string
Hostname string Hostname string
Host string
PubCert string PubCert string
Client *resty.Client Client *resty.Client
} }
...@@ -17,7 +17,7 @@ func GetInstance() *Globals { ...@@ -17,7 +17,7 @@ func GetInstance() *Globals {
return globals return globals
} }
func Init(hostname string, host string, pubCert string, client *resty.Client) *Globals { func Init(hostname string, host string, pubCert string, client *resty.Client) {
return &Globals{hostname, host, pubCert, client} globals = &Globals{hostname, host, pubCert, client}
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment