diff --git a/docs/README_server.md b/docs/README_server.md index 16340f61bcd4177e186583595a376059412b775a..814f0e59a4720d7e16559eba98b4d2c1bb6e57c4 100644 --- a/docs/README_server.md +++ b/docs/README_server.md @@ -338,6 +338,7 @@ These capabilities are called "VM access capabilities": | Route | Description | Method | Parameters | Req. user cap. | Op. | Req. VM access cap. | |--- |--- |--- |--- |--- |--- |--- | | `/vms` | returns VMs that can be listed | GET | | `VM_LIST_ANY` | OR | `VM_LIST` | +| `/vms/{id}` | returns a VM | GET | | `VM_LIST_ANY` | OR | `VM_LIST` | | `/vms/start` | returns VMs that can be started | GET | | `VM_START_ANY` | OR | `VM_START` | | `/vms/attach` | returns VMs that can be attached to | GET | | `VM_LIST_ANY` | OR | `VM_LIST` | | `/vms/stop` | returns VMs that can be killed/shutdown | GET | | `VM_STOP_ANY` | OR | `VM_STOP` | @@ -354,7 +355,6 @@ These capabilities are called "VM access capabilities": | `/vms/{id}` | delete a VM | DELETE | | `VM_DESTROY_ANY` | OR | `VM_DESTROY` | | `/vms/{id}` | edit a VM | PUT | name,cpus,ram,nic,usb | `VM_EDIT_ANY` | OR | `VM_EDIT` | | `/vms/{id}/start` | start a VM | PUT | | `VM_START_ANY` | OR | `VM_START` | -| `/vms/{id}/start` | start a VM | PUT | | `VM_START_ANY` | OR | `VM_START` | | `/vms/{id}/startwithcreds` | start a VM with credentials | PUT | port,pwd | `VM_START_ANY` | OR | `VM_START` | | `/vms/{id}/stop` | kill a VM | PUT | | `VM_STOP_ANY` | OR | `VM_STOP` | | `/vms/{id}/reboot` | reboot a VM | PUT | | `VM_REBOOT_ANY` | OR | `VM_REBOOT` | diff --git a/src/client/nexush/nexush.go b/src/client/nexush/nexush.go index 6b92a799f90f36c202411e7d059b67033e73b053..5787b35be8514d615c47458c655db3f272f9f859 100644 --- a/src/client/nexush/nexush.go +++ b/src/client/nexush/nexush.go @@ -63,6 +63,7 @@ var cmdList = []cmd.Command { &cmdVM.ImportDir{"vmimportdir"}, &cmdVM.Stop{"vmkill"}, &cmdVM.List{"vmlist"}, + &cmdVM.ListSingle{"vmlistsingle"}, &cmdVM.Reboot{"vmreboot"}, &cmdVM.Shutdown{"vmshutdown"}, &cmdVM.Start{"vmstart"}, diff --git a/src/server/router/router.go b/src/server/router/router.go index d4f471db6b539c44f95ec5b392ed111cd77c649f..e35b910db1d83ca56ff73a0561138d8b2c9afe89 100644 --- a/src/server/router/router.go +++ b/src/server/router/router.go @@ -71,6 +71,7 @@ func (router *Router)Start(port int) { // VM management. vmsGroup := router.echo.Group("/vms") vmsGroup.Use(middleware.JWTWithConfig(auth.GetTokenAccess())) + vmsGroup.GET("/:id", router.vms.GetListableVM) vmsGroup.GET("", router.vms.GetListableVMs) vmsGroup.GET("/attach", router.vms.GetAttachableVMs) vmsGroup.GET("/del", router.vms.GetDeletableVMs) diff --git a/src/server/router/routerVMs.go b/src/server/router/routerVMs.go index 34cca62f1651ca66f79599623ac1483c4c102f12..d687db857ce89e1f16e06fc8d35f86f2b957ec10 100644 --- a/src/server/router/routerVMs.go +++ b/src/server/router/routerVMs.go @@ -40,6 +40,50 @@ func (r *RouterVMs)GetListableVMs(c echo.Context) error { }) } +// Returns a VM that can be listed based on its UUID. +// Requires to be the VM's owner, or either capability: +// 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. +// curl --cacert ca.pem -X GET https://localhost:1077/vm/62ae8791-c108-4235-a7d6-074e9b6a9017 -H "Authorization: Bearer <AccessToken>" +func (r *RouterVMs)GetListableVM(c echo.Context) error { + // Retrieves the VM based on its UUID. + id, err := uuid.Parse(c.Param("id")) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, err.Error()) + } + vm, err := r.vms.GetVM(id) + if err != nil { + 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.HasCapability(caps.CAP_VM_LIST_ANY) { + return c.JSONPretty(http.StatusOK, vm.SerializeToNetwork(), " ") + } else { + if vm.IsOwner(user.Email) { + return c.JSONPretty(http.StatusOK, vm.SerializeToNetwork(), " ") + } else { + capabilities, exists := vm.GetAccess()[user.Email] + if exists { + _, found := capabilities[caps.CAP_VM_LIST] + if found { + return c.JSONPretty(http.StatusOK, vm.SerializeToNetwork(), " ") + } else { + return echo.NewHTTPError(http.StatusUnauthorized, msgInsufficientCaps) + } + } else { + return echo.NewHTTPError(http.StatusUnauthorized, msgInsufficientCaps) + } + } + } +} + // Returns VMs that are running and that can be attached to. // Requires to be the VM's owner, or either capability: // User cap: CAP_VM_LIST_ANY: returns all running VMs. diff --git a/src/server/vms/vm.go b/src/server/vms/vm.go index 95d9cd7d81e502ff5955de391324d1dd74603eb8..ea8662f46b7947daeb56c5e433c79a0cad3f5383 100644 --- a/src/server/vms/vm.go +++ b/src/server/vms/vm.go @@ -84,7 +84,7 @@ func NewVM(creatorEmail string, name string, cpus, ram int, nic vmc.NicType, usb return vm, nil } -// Returns a serialized version (to be written to disk) of the template. +// Returns a serialized version (to be written to disk) of the VM. // Concurrency: safe func (vm *VM)SerializeToDisk() vmc.VMDiskSerialized { return vmc.VMDiskSerialized { @@ -100,7 +100,7 @@ func (vm *VM)SerializeToDisk() vmc.VMDiskSerialized { } } -// Returns a serialized version (to be sent to the network) of the template. +// Returns a serialized version (to be sent to the network) of the VM. // Concurrency: safe func (vm *VM)SerializeToNetwork() vmc.VMNetworkSerialized { return vmc.VMNetworkSerialized {