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

server:

- added route to retrieve a single VM from its UUID
- added route to retrieve a single template from its UUID

client:
- added vmlistsingle to test above route (but then commented out)
- added tpllistsingle to test above route (but then commented out)
parent 1a1b9204
Branches
No related tags found
No related merge requests found
...@@ -368,12 +368,13 @@ These capabilities are called "VM access capabilities": ...@@ -368,12 +368,13 @@ These capabilities are called "VM access capabilities":
| Route | Description | Method | Parameters | Req. user cap. | | Route | Description | Method | Parameters | Req. user cap. |
|--- |--- |--- |--- |--- | |--- |--- |--- |--- |--- |
| `/templates` | returns templates that can be listed | GET | | `TPL_LIST_ANY` OR `TPL_LIST` |
| `/templates/{id}` | returns a template | GET | | `TPL_LIST_ANY` OR `TPL_LIST` |
| `/templates/vm` | create a template | POST | vmID,name,access | `TPL_CREATE` | | `/templates/vm` | create a template | POST | vmID,name,access | `TPL_CREATE` |
| `/templates/qcow` | create a template | POST | qcow,name,access | `TPL_CREATE` | | `/templates/qcow` | create a template | POST | qcow,name,access | `TPL_CREATE` |
| `/templates/{id}` | edit a template | PUT | name,access | `TPL_EDIT_ANY` OR `TPL_EDIT` | | `/templates/{id}` | edit a template | PUT | name,access | `TPL_EDIT_ANY` OR `TPL_EDIT` |
| `/templates/{id}` | delete a template | DELETE | | `TPL_DESTROY_ANY` OR `TPL_DESTROY` | | `/templates/{id}` | delete a template | DELETE | | `TPL_DESTROY_ANY` OR `TPL_DESTROY` |
| `/templates/{id}/disk` | download a template's disk | GET | | `TPL_READFS_ANY` OR `TPL_READFS` | | `/templates/{id}/disk` | download a template's disk | GET | | `TPL_READFS_ANY` OR `TPL_READFS` |
| `/templates` | list templates | GET | | `TPL_LIST_ANY` OR `TPL_LIST` |
Remarks: Remarks:
......
...@@ -141,7 +141,7 @@ func getFilteredTemplates(route string, patterns []string) ([]t.TemplateSerializ ...@@ -141,7 +141,7 @@ func getFilteredTemplates(route string, patterns []string) ([]t.TemplateSerializ
templatesList := []t.TemplateSerialized{} templatesList := []t.TemplateSerialized{}
if resp.IsSuccess() { if resp.IsSuccess() {
templates, err := getTemplates(resp) templates, err := deserializeTemplates(resp)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -176,11 +176,20 @@ func getFilteredTemplates(route string, patterns []string) ([]t.TemplateSerializ ...@@ -176,11 +176,20 @@ func getFilteredTemplates(route string, patterns []string) ([]t.TemplateSerializ
} }
} }
// Retrieves all templates (no filtering). // Deserialize a list of templates from an http response (no filtering).
func getTemplates(resp *resty.Response) ([]t.TemplateSerialized, error) { func deserializeTemplates(resp *resty.Response) ([]t.TemplateSerialized, error) {
templates := []t.TemplateSerialized{} templates := []t.TemplateSerialized{}
if err := json.Unmarshal(resp.Body(), &templates); err != nil { if err := json.Unmarshal(resp.Body(), &templates); err != nil {
return nil, err return nil, err
} }
return templates, nil return templates, nil
} }
// Deserialize a single template from an http response.
func deserializeTemplate(resp *resty.Response) (*t.TemplateSerialized, error) {
var tpl *t.TemplateSerialized = &t.TemplateSerialized{}
if err := json.Unmarshal(resp.Body(), &tpl); err != nil {
return tpl, err
}
return tpl, nil
}
...@@ -134,7 +134,7 @@ func getFilteredVMs(route string, patterns []string) ([]vm.VMNetworkSerialized, ...@@ -134,7 +134,7 @@ func getFilteredVMs(route string, patterns []string) ([]vm.VMNetworkSerialized,
vmsList := []vm.VMNetworkSerialized{} vmsList := []vm.VMNetworkSerialized{}
if resp.IsSuccess() { if resp.IsSuccess() {
vms, err := getVMs(resp) vms, err := deserializeVMs(resp)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -169,8 +169,8 @@ func getFilteredVMs(route string, patterns []string) ([]vm.VMNetworkSerialized, ...@@ -169,8 +169,8 @@ func getFilteredVMs(route string, patterns []string) ([]vm.VMNetworkSerialized,
} }
} }
// Retrieves all VMs (no filtering). // Deserialize a list of VMs from an http response (no filtering).
func getVMs(resp *resty.Response) ([]vm.VMNetworkSerialized, error) { func deserializeVMs(resp *resty.Response) ([]vm.VMNetworkSerialized, error) {
vms := []vm.VMNetworkSerialized{} vms := []vm.VMNetworkSerialized{}
if err := json.Unmarshal(resp.Body(), &vms); err != nil { if err := json.Unmarshal(resp.Body(), &vms); err != nil {
return nil, err return nil, err
...@@ -178,8 +178,8 @@ func getVMs(resp *resty.Response) ([]vm.VMNetworkSerialized, error) { ...@@ -178,8 +178,8 @@ func getVMs(resp *resty.Response) ([]vm.VMNetworkSerialized, error) {
return vms, nil return vms, nil
} }
// Retrieve a single VM. // Deserialize a single VM from an http response.
func getVM(resp *resty.Response) (*vm.VMNetworkSerialized, error) { func deserializeVM(resp *resty.Response) (*vm.VMNetworkSerialized, error) {
var vm *vm.VMNetworkSerialized = &vm.VMNetworkSerialized{} var vm *vm.VMNetworkSerialized = &vm.VMNetworkSerialized{}
if err := json.Unmarshal(resp.Body(), vm); err != nil { if err := json.Unmarshal(resp.Body(), vm); err != nil {
return vm, err return vm, err
......
...@@ -138,7 +138,7 @@ func (cmd *Create)Run(args []string) int { ...@@ -138,7 +138,7 @@ func (cmd *Create)Run(args []string) int {
statusCode = 1 statusCode = 1
} else { } else {
if resp.IsSuccess() { if resp.IsSuccess() {
vm, err := getVM(resp) vm, err := deserializeVM(resp)
if err != nil { if err != nil {
u.PrintlnErr("Failed retrieving server's response: "+err.Error()) u.PrintlnErr("Failed retrieving server's response: "+err.Error())
statusCode = 1 statusCode = 1
......
...@@ -45,7 +45,7 @@ func (cmd *ListSingle)Run(args []string) int { ...@@ -45,7 +45,7 @@ func (cmd *ListSingle)Run(args []string) int {
return 1 return 1
} else { } else {
if resp.IsSuccess() { if resp.IsSuccess() {
vm, err := getVM(resp) vm, err := deserializeVM(resp)
if err != nil { if err != nil {
u.PrintlnErr("Failed retrieving server's response: "+err.Error()) u.PrintlnErr("Failed retrieving server's response: "+err.Error())
return 1 return 1
......
...@@ -49,6 +49,7 @@ var cmdList = []cmd.Command { ...@@ -49,6 +49,7 @@ var cmdList = []cmd.Command {
&cmdTemplate.Edit{"tpledit"}, &cmdTemplate.Edit{"tpledit"},
&cmdTemplate.ExportDisk{"tplexportdisk"}, &cmdTemplate.ExportDisk{"tplexportdisk"},
&cmdTemplate.List{"tpllist"}, &cmdTemplate.List{"tpllist"},
// &cmdTemplate.ListSingle{"tpllistsingle"}, // for testing the route only
&cmdMisc.HelpHeader{"!═════╡ VM commands ╞═════════════════════════════════════════════════════════════════"}, &cmdMisc.HelpHeader{"!═════╡ VM commands ╞═════════════════════════════════════════════════════════════════"},
&cmdVM.AddAccess{"vmaddaccess"}, &cmdVM.AddAccess{"vmaddaccess"},
...@@ -63,7 +64,7 @@ var cmdList = []cmd.Command { ...@@ -63,7 +64,7 @@ var cmdList = []cmd.Command {
&cmdVM.ImportDir{"vmimportdir"}, &cmdVM.ImportDir{"vmimportdir"},
&cmdVM.Stop{"vmkill"}, &cmdVM.Stop{"vmkill"},
&cmdVM.List{"vmlist"}, &cmdVM.List{"vmlist"},
&cmdVM.ListSingle{"vmlistsingle"}, // &cmdVM.ListSingle{"vmlistsingle"}, // for testing the route only
&cmdVM.Reboot{"vmreboot"}, &cmdVM.Reboot{"vmreboot"},
&cmdVM.Shutdown{"vmshutdown"}, &cmdVM.Shutdown{"vmshutdown"},
&cmdVM.Start{"vmstart"}, &cmdVM.Start{"vmstart"},
......
...@@ -99,6 +99,7 @@ func (router *Router)Start(port int) { ...@@ -99,6 +99,7 @@ func (router *Router)Start(port int) {
// Template management. // Template management.
templatesGroup := router.echo.Group("/templates") templatesGroup := router.echo.Group("/templates")
templatesGroup.Use(middleware.JWTWithConfig(auth.GetTokenAccess())) templatesGroup.Use(middleware.JWTWithConfig(auth.GetTokenAccess()))
templatesGroup.GET("/:id", router.tpl.GetTemplate)
templatesGroup.GET("", router.tpl.GetTemplates) templatesGroup.GET("", router.tpl.GetTemplates)
templatesGroup.POST("/vm", router.tpl.CreateTemplateFromVM) templatesGroup.POST("/vm", router.tpl.CreateTemplateFromVM)
templatesGroup.POST("/qcow", router.tpl.CreateTemplateFromQCOW) templatesGroup.POST("/qcow", router.tpl.CreateTemplateFromQCOW)
......
...@@ -52,6 +52,41 @@ func (r *RouterTemplates)GetTemplates(c echo.Context) error { ...@@ -52,6 +52,41 @@ func (r *RouterTemplates)GetTemplates(c echo.Context) error {
} }
} }
// Returns a template that can be listed based on its UUID.
// Requires either capability:
// CAP_TPL_LIST_ANY: any templates can be listed.
// CAP_TPL_LIST: only templates owned by the user as well as public templates can be listed.
// curl --cacert ca.pem -X GET https://localhost:1077/templates/62ae8791-c108-4235-a7d6-074e9b6a9017 -H "Authorization: Bearer <AccessToken>"
func (r *RouterTemplates)GetTemplate(c echo.Context) error {
// Retrieves logged user from context.
user, err := getLoggedUser(r.users, c)
if err != nil {
return echo.NewHTTPError(http.StatusUnauthorized, err.Error())
}
// Retrieves the template based on its UUID.
id, err := uuid.Parse(c.Param("id"))
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, err.Error())
}
tpl, err := r.tpl.GetTemplate(id)
if err != nil {
return echo.NewHTTPError(http.StatusNotFound, err.Error())
}
// If user has CAP_TPL_LIST_ANY, returns the template.
if user.HasCapability(caps.CAP_TPL_LIST_ANY) {
return c.JSONPretty(http.StatusOK, tpl.SerializeToNetwork(), " ")
} else if user.HasCapability(caps.CAP_TPL_LIST) {
// Returns template if owned by the user or template is public.
if tpl.GetOwner() == user.Email || tpl.IsPublic() {
return c.JSONPretty(http.StatusOK, tpl.SerializeToNetwork(), " ")
}
}
return echo.NewHTTPError(http.StatusUnauthorized, msgInsufficientCaps)
}
// Creates a template from a VM. // Creates a template from a VM.
// Requires CAP_TPL_CREATE. // Requires CAP_TPL_CREATE.
// curl --cacert ca.pem -X POST https://localhost:1077/templates/vm -H 'Content-Type: application/json' -d '{"vmID":"e41f3556-ca24-4658-bd79-8c85bd6bff59","name":"Xubuntu_22.04","access":"public"}' -H "Authorization: Bearer <AccessToken>" // curl --cacert ca.pem -X POST https://localhost:1077/templates/vm -H 'Content-Type: application/json' -d '{"vmID":"e41f3556-ca24-4658-bd79-8c85bd6bff59","name":"Xubuntu_22.04","access":"public"}' -H "Authorization: Bearer <AccessToken>"
......
...@@ -3,7 +3,6 @@ package router ...@@ -3,7 +3,6 @@ package router
import ( import (
"io" "io"
"os" "os"
// "errors"
"net/http" "net/http"
"path/filepath" "path/filepath"
"nexus-common/caps" "nexus-common/caps"
...@@ -44,8 +43,14 @@ func (r *RouterVMs)GetListableVMs(c echo.Context) error { ...@@ -44,8 +43,14 @@ func (r *RouterVMs)GetListableVMs(c echo.Context) error {
// Requires to be the VM's owner, or either capability: // Requires to be the VM's owner, or either capability:
// User cap: CAP_VM_LIST_ANY: returns the VM. // User cap: CAP_VM_LIST_ANY: returns the VM.
// VM access cap: CAP_VM_LIST: returns the VM with this cap for the logged user. // VM access cap: CAP_VM_LIST: returns the VM with this cap for the logged user.
// curl --cacert ca.pem -X GET https://localhost:1077/vm/62ae8791-c108-4235-a7d6-074e9b6a9017 -H "Authorization: Bearer <AccessToken>" // curl --cacert ca.pem -X GET https://localhost:1077/vms/62ae8791-c108-4235-a7d6-074e9b6a9017 -H "Authorization: Bearer <AccessToken>"
func (r *RouterVMs)GetListableVM(c echo.Context) error { func (r *RouterVMs)GetListableVM(c echo.Context) error {
// Retrieves logged user from context.
user, err := getLoggedUser(r.users, c)
if err != nil {
return echo.NewHTTPError(http.StatusUnauthorized, err.Error())
}
// Retrieves the VM based on its UUID. // Retrieves the VM based on its UUID.
id, err := uuid.Parse(c.Param("id")) id, err := uuid.Parse(c.Param("id"))
if err != nil { if err != nil {
...@@ -56,12 +61,6 @@ func (r *RouterVMs)GetListableVM(c echo.Context) error { ...@@ -56,12 +61,6 @@ func (r *RouterVMs)GetListableVM(c echo.Context) error {
return echo.NewHTTPError(http.StatusNotFound, err.Error()) return echo.NewHTTPError(http.StatusNotFound, err.Error())
} }
// Retrieves logged user from context.
user, err := getLoggedUser(r.users, c)
if err != nil {
return echo.NewHTTPError(http.StatusUnauthorized, err.Error())
}
// If user has CAP_VM_LIST_ANY capability, returns the VM. // If user has CAP_VM_LIST_ANY capability, returns the VM.
if user.HasCapability(caps.CAP_VM_LIST_ANY) { if user.HasCapability(caps.CAP_VM_LIST_ANY) {
return c.JSONPretty(http.StatusOK, vm.SerializeToNetwork(), " ") return c.JSONPretty(http.StatusOK, vm.SerializeToNetwork(), " ")
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment