Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
S
Secure solution for nexus infrastructure
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
flg_masters
TM
Secure solution for nexus infrastructure
Commits
dd105eeb
Commit
dd105eeb
authored
2 years ago
by
Florent Gluck
Browse files
Options
Downloads
Patches
Plain Diff
Fixed minor mistake in README.md
Reworked VMs code a bit to have more conistent behavior among methods
parent
2ccbcbeb
No related branches found
No related tags found
No related merge requests found
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
README.md
+2
-2
2 additions, 2 deletions
README.md
src/router/routerTemplates.go
+1
-1
1 addition, 1 deletion
src/router/routerTemplates.go
src/router/routerVMs.go
+70
-70
70 additions, 70 deletions
src/router/routerVMs.go
src/vms/vms.go
+53
-47
53 additions, 47 deletions
src/vms/vms.go
with
126 additions
and
120 deletions
README.md
+
2
−
2
View file @
dd105eeb
...
...
@@ -375,8 +375,8 @@ Legend for the "Done" column:
| Done | Route | Description | Method | Parameters | Req. user cap. |
|--- |--- |--- |--- |--- |--- |
| x |
`/templates/vm`
| create a template | POST | vmID,name,
descr,
access |
`TPL_CREATE`
|
| x |
`/templates/qcow`
| create a template | POST | qcow,name,
descr,
access |
`TPL_CREATE`
|
| x |
`/templates/vm`
| create a template | POST | vmID,name,access
|
`TPL_CREATE`
|
| x |
`/templates/qcow`
| create a template | POST | qcow,name,access
|
`TPL_CREATE`
|
| x |
`/templates/{id}`
| delete a template | DELETE | |
`TPL_DESTROY_ANY|TPL_DESTROY`
|
| x |
`/templates`
| list templates | GET | |
`TPL_LIST_ANY|TPL_LIST`
|
...
...
This diff is collapsed.
Click to expand it.
src/router/routerTemplates.go
+
1
−
1
View file @
dd105eeb
...
...
@@ -185,7 +185,7 @@ func (r *RouterTemplates)CreateTemplateFromQCOW(c echo.Context) error {
// CAP_TPL_DESTROY_ANY: any template can be deleted.
// CAP_TPL_DESTROY: only a template owned by the user can be deleted.
// Remark: a template can only be deleted if no VM references it!
// curl --cacert ca.pem -X DELETE https://localhost:1077/templates/
Xubuntu_22.04_+_gcc_+_vscodium
-H "Authorization: Bearer <AccessToken>"
// curl --cacert ca.pem -X DELETE https://localhost:1077/templates/
4913a2bb-edfe-4dfe-af53-38197a44523b
-H "Authorization: Bearer <AccessToken>"
func
(
r
*
RouterTemplates
)
DeleteTemplateByID
(
c
echo
.
Context
)
error
{
// Retrieves logged user from context.
user
,
err
:=
getLoggedUser
(
r
.
users
,
c
)
...
...
This diff is collapsed.
Click to expand it.
src/router/routerVMs.go
+
70
−
70
View file @
dd105eeb
...
...
@@ -359,75 +359,6 @@ func (r *RouterVMs)DeleteVMAccessForUser(c echo.Context) error {
return
c
.
JSONPretty
(
http
.
StatusOK
,
jsonMsg
(
"OK"
),
" "
)
}
// Helper function that returns a list of VMs that match either:
// - the logged user has the userCapabilityAny capability.
// - the VM access for the logged user matches the vmAccessCapability capability.
// Also, VMs for which cond is false are filtered out.
func
(
r
*
RouterVMs
)
performVMsList
(
c
echo
.
Context
,
userCapabilityAny
,
vmAccessCapability
string
,
cond
vms
.
VMKeeperFn
)
error
{
// Retrieves logged user from context.
user
,
err
:=
getLoggedUser
(
r
.
users
,
c
)
if
err
!=
nil
{
return
echo
.
NewHTTPError
(
http
.
StatusUnauthorized
,
err
.
Error
())
}
// If the logged user has the XX_ANY capability (userCapabilityAny), returns all VMs.
if
user
.
HasCapability
(
userCapabilityAny
)
{
// Returns all VMs that pass the condition.
return
c
.
JSONPretty
(
http
.
StatusOK
,
r
.
vms
.
GetVMs
(
cond
),
" "
)
}
else
{
// Returns all VMs for which VM access for the logged user matches the specified the VM Access capability (vmAccessCapability).
return
c
.
JSONPretty
(
http
.
StatusOK
,
r
.
vms
.
GetVMs
(
func
(
vm
vms
.
VM
)
bool
{
capabilities
,
exists
:=
vm
.
Access
[
user
.
Email
]
if
exists
{
_
,
visible
:=
capabilities
[
vmAccessCapability
]
return
visible
&&
cond
(
vm
)
}
else
{
return
false
}
}),
" "
)
}
}
// Helper function that performs an action on a VM based either on:
// - the logged user has the userCapabilityAny capability.
// - the VM access for the logged user matches the vmAccessCapability capability.
func
(
r
*
RouterVMs
)
performVMAction
(
c
echo
.
Context
,
userCapabilityAny
,
vmAccessCapability
string
,
action
vmActionFn
)
error
{
// Retrieves the VM on which to perform the action.
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 the logged user from context.
user
,
err
:=
getLoggedUser
(
r
.
users
,
c
)
if
err
!=
nil
{
return
echo
.
NewHTTPError
(
http
.
StatusUnauthorized
,
err
.
Error
())
}
// First, checks if the user has the XX_ANY capability
if
user
.
HasCapability
(
userCapabilityAny
)
{
return
action
(
c
,
&
vm
)
}
else
{
// Check if the VM access for the logged user matches the required capability
userCaps
,
exists
:=
vm
.
Access
[
user
.
Email
]
if
!
exists
{
return
echo
.
NewHTTPError
(
http
.
StatusUnauthorized
,
msgInsufficientCaps
)
}
_
,
hasAccess
:=
userCaps
[
vmAccessCapability
]
if
!
hasAccess
{
return
echo
.
NewHTTPError
(
http
.
StatusUnauthorized
,
msgInsufficientCaps
)
}
return
action
(
c
,
&
vm
)
}
}
// Exports a VM's directory into a .tar archive.
// Requires either capability:
// User cap: VM_READFS_ANY: any VM can have their filesystem read.
...
...
@@ -512,3 +443,72 @@ func (r *RouterVMs)ImportFilesToVM(c echo.Context) error {
return
c
.
JSONPretty
(
http
.
StatusCreated
,
jsonMsg
(
"OK"
),
" "
)
})
}
// Helper function that returns a list of VMs that match either:
// - the logged user has the userCapabilityAny capability.
// - the VM access for the logged user matches the vmAccessCapability capability.
// Also, VMs for which cond is false are filtered out.
func
(
r
*
RouterVMs
)
performVMsList
(
c
echo
.
Context
,
userCapabilityAny
,
vmAccessCapability
string
,
cond
vms
.
VMKeeperFn
)
error
{
// Retrieves logged user from context.
user
,
err
:=
getLoggedUser
(
r
.
users
,
c
)
if
err
!=
nil
{
return
echo
.
NewHTTPError
(
http
.
StatusUnauthorized
,
err
.
Error
())
}
// If the logged user has the XX_ANY capability (userCapabilityAny), returns all VMs.
if
user
.
HasCapability
(
userCapabilityAny
)
{
// Returns all VMs that pass the condition.
return
c
.
JSONPretty
(
http
.
StatusOK
,
r
.
vms
.
GetVMs
(
cond
),
" "
)
}
else
{
// Returns all VMs for which VM access for the logged user matches the specified the VM Access capability (vmAccessCapability).
return
c
.
JSONPretty
(
http
.
StatusOK
,
r
.
vms
.
GetVMs
(
func
(
vm
vms
.
VM
)
bool
{
capabilities
,
exists
:=
vm
.
Access
[
user
.
Email
]
if
exists
{
_
,
visible
:=
capabilities
[
vmAccessCapability
]
return
visible
&&
cond
(
vm
)
}
else
{
return
false
}
}),
" "
)
}
}
// Helper function that performs an action on a VM based either on:
// - the logged user has the userCapabilityAny capability.
// - the VM access for the logged user matches the vmAccessCapability capability.
func
(
r
*
RouterVMs
)
performVMAction
(
c
echo
.
Context
,
userCapabilityAny
,
vmAccessCapability
string
,
action
vmActionFn
)
error
{
// Retrieves the VM on which to perform the action.
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 the logged user from context.
user
,
err
:=
getLoggedUser
(
r
.
users
,
c
)
if
err
!=
nil
{
return
echo
.
NewHTTPError
(
http
.
StatusUnauthorized
,
err
.
Error
())
}
// First, checks if the user has the XX_ANY capability
if
user
.
HasCapability
(
userCapabilityAny
)
{
return
action
(
c
,
&
vm
)
}
else
{
// Check if the VM access for the logged user matches the required capability
userCaps
,
exists
:=
vm
.
Access
[
user
.
Email
]
if
!
exists
{
return
echo
.
NewHTTPError
(
http
.
StatusUnauthorized
,
msgInsufficientCaps
)
}
_
,
hasAccess
:=
userCaps
[
vmAccessCapability
]
if
!
hasAccess
{
return
echo
.
NewHTTPError
(
http
.
StatusUnauthorized
,
msgInsufficientCaps
)
}
return
action
(
c
,
&
vm
)
}
}
This diff is collapsed.
Click to expand it.
src/vms/vms.go
+
53
−
47
View file @
dd105eeb
...
...
@@ -94,11 +94,11 @@ func InitVMs() error {
}
// Returns the list of VMs for which VMKeeperFn returns true.
func
(
vms
*
VMs
)
GetVMs
(
keep
VMKeeperFn
)
[]
VM
{
func
(
vms
*
VMs
)
GetVMs
(
keep
Fn
VMKeeperFn
)
[]
VM
{
vms
.
rwlock
.
RLock
()
list
:=
[]
VM
{}
for
_
,
vm
:=
range
vms
.
m
{
if
keep
(
vm
)
{
if
keep
Fn
(
vm
)
{
list
=
append
(
list
,
vm
)
}
}
...
...
@@ -115,6 +115,10 @@ func (vms *VMs)GetVMs(keep VMKeeperFn) []VM {
func
(
vms
*
VMs
)
GetVM
(
vmID
uuid
.
UUID
)
(
VM
,
error
)
{
vms
.
rwlock
.
RLock
()
defer
vms
.
rwlock
.
RUnlock
()
return
vms
.
getVMUnsafe
(
vmID
)
}
func
(
vms
*
VMs
)
getVMUnsafe
(
vmID
uuid
.
UUID
)
(
VM
,
error
)
{
vm
,
exists
:=
vms
.
m
[
vmID
.
String
()]
if
!
exists
{
return
dummyVM
,
errors
.
New
(
"VM not found"
)
...
...
@@ -123,12 +127,15 @@ func (vms *VMs)GetVM(vmID uuid.UUID) (VM, error) {
}
// Deletes a VM by its ID and deletes its files.
func
(
vms
*
VMs
)
DeleteVM
(
id
uuid
.
UUID
)
error
{
key
:=
id
.
String
()
func
(
vms
*
VMs
)
DeleteVM
(
vmID
uuid
.
UUID
)
error
{
vms
.
rwlock
.
Lock
()
defer
vms
.
rwlock
.
Unlock
()
vm
,
exists
:=
vms
.
m
[
key
]
if
exists
{
vm
,
err
:=
vms
.
getVMUnsafe
(
vmID
)
if
err
!=
nil
{
return
err
}
// Deletes the VM's files (and directories).
vm
.
mutex
.
Lock
()
if
err
:=
vm
.
delete
();
err
!=
nil
{
...
...
@@ -137,11 +144,9 @@ func (vms *VMs)DeleteVM(id uuid.UUID) error {
}
vm
.
mutex
.
Unlock
()
// Removes the VM from the map.
delete
(
vms
.
m
,
key
)
delete
(
vms
.
m
,
vm
.
ID
.
String
()
)
return
nil
}
return
errors
.
New
(
"VM not found"
)
}
// Adds a VM and writes its files.
func
(
vms
*
VMs
)
AddVM
(
vm
*
VM
)
error
{
...
...
@@ -165,13 +170,13 @@ func (vms *VMs)AddVM(vm *VM) error {
// Starts a VM by its ID.
// Returns the port on which the VM is running and the access password.
func
(
vms
*
VMs
)
StartVM
(
id
uuid
.
UUID
)
(
int
,
string
,
error
)
{
func
(
vms
*
VMs
)
StartVM
(
vmID
uuid
.
UUID
)
(
int
,
string
,
error
)
{
vms
.
rwlock
.
Lock
()
defer
vms
.
rwlock
.
Unlock
()
vm
,
e
xists
:=
vms
.
m
[
id
.
String
()]
if
!
exists
{
return
-
1
,
""
,
err
ors
.
New
(
"VM not found"
)
vm
,
e
rr
:=
vms
.
getVMUnsafe
(
vmID
)
if
err
!=
nil
{
return
0
,
""
,
err
}
// Check there will be at least 1GB of RAM left after the VM has started,
...
...
@@ -215,33 +220,33 @@ func (vms *VMs)StartVM(id uuid.UUID) (int, string, error) {
}
// Stops by force a VM by its ID.
func
(
vms
*
VMs
)
StopVM
(
id
uuid
.
UUID
)
error
{
func
(
vms
*
VMs
)
StopVM
(
vmID
uuid
.
UUID
)
error
{
vms
.
rwlock
.
RLock
()
defer
vms
.
rwlock
.
RUnlock
()
vm
,
e
xists
:=
vms
.
m
[
id
.
String
()]
if
!
exists
{
return
err
ors
.
New
(
"VM not found"
)
vm
,
e
rr
:=
vms
.
getVMUnsafe
(
vmID
)
if
err
!=
nil
{
return
err
}
vm
.
mutex
.
Lock
()
err
:
=
vm
.
stop
()
err
=
vm
.
stop
()
vm
.
mutex
.
Unlock
()
return
err
}
// Gracefully stops a VM by its ID.
func
(
vms
*
VMs
)
ShutdownVM
(
id
uuid
.
UUID
)
error
{
func
(
vms
*
VMs
)
ShutdownVM
(
vmID
uuid
.
UUID
)
error
{
vms
.
rwlock
.
Lock
()
defer
vms
.
rwlock
.
Unlock
()
vm
,
e
xists
:=
vms
.
m
[
id
.
String
()]
if
!
exists
{
return
err
ors
.
New
(
"VM not found"
)
vm
,
e
rr
:=
vms
.
getVMUnsafe
(
vmID
)
if
err
!=
nil
{
return
err
}
vm
.
mutex
.
Lock
()
err
:
=
vm
.
shutdown
()
err
=
vm
.
shutdown
()
vm
.
mutex
.
Unlock
()
return
err
}
...
...
@@ -261,10 +266,9 @@ func (vms *VMs)IsTemplateUsed(templateID string) bool {
// Edit a VM' specs: name, cpus, ram, nic
func
(
vms
*
VMs
)
EditVM
(
vmID
uuid
.
UUID
,
name
string
,
cpus
,
ram
int
,
nic
NicType
)
error
{
// Retrieves the VM to be edited.
vm
,
err
:=
vms
.
GetVM
(
vmID
)
vm
,
err
:=
vms
.
getVMUnsafe
(
vmID
)
if
err
!=
nil
{
return
err
ors
.
New
(
"VM not found"
)
return
err
}
// Only updates fields that have changed.
...
...
@@ -305,12 +309,18 @@ func (vms *VMs)SetVMAccess(vmID uuid.UUID, loggedUserEmail, userEmail string, ne
return
errors
.
New
(
"Invalid capability"
)
}
vms
.
rwlock
.
Lock
()
defer
vms
.
rwlock
.
Unlock
()
// Retrieves the VM for which the access caps must be changed.
vm
,
err
:=
vms
.
G
etVM
(
vmID
)
vm
,
err
:=
vms
.
g
etVM
Unsafe
(
vmID
)
if
err
!=
nil
{
return
err
ors
.
New
(
"VM not found"
)
return
err
}
vm
.
mutex
.
Lock
()
defer
vm
.
mutex
.
Unlock
()
// Checks the logged user has VM_SET_ACCESS set in her/his VM access.
userCaps
:=
vm
.
Access
[
loggedUserEmail
]
_
,
exists
:=
userCaps
[
caps
.
CAP_VM_SET_ACCESS
]
...
...
@@ -320,11 +330,6 @@ func (vms *VMs)SetVMAccess(vmID uuid.UUID, loggedUserEmail, userEmail string, ne
vm
.
Access
[
userEmail
]
=
newAccess
vm
.
mutex
.
Lock
()
defer
vm
.
mutex
.
Unlock
()
vms
.
rwlock
.
Lock
()
defer
vms
.
rwlock
.
Unlock
()
if
err
=
vms
.
updateVM
(
&
vm
);
err
!=
nil
{
return
errors
.
New
(
"Failed updating VM"
)
}
...
...
@@ -336,12 +341,18 @@ func (vms *VMs)SetVMAccess(vmID uuid.UUID, loggedUserEmail, userEmail string, ne
// loggedUserEmail is the email of the currently logged user
// userMail is the email of the user for which to remove the access
func
(
vms
*
VMs
)
DeleteVMAccess
(
vmID
uuid
.
UUID
,
loggedUserEmail
,
userEmail
string
)
error
{
vms
.
rwlock
.
Lock
()
defer
vms
.
rwlock
.
Unlock
()
// Retrieves the VM for which the access caps must be changed.
vm
,
err
:=
vms
.
G
etVM
(
vmID
)
vm
,
err
:=
vms
.
g
etVM
Unsafe
(
vmID
)
if
err
!=
nil
{
return
err
ors
.
New
(
"VM not found"
)
return
err
}
vm
.
mutex
.
Lock
()
defer
vm
.
mutex
.
Unlock
()
// Checks the user has VM_SET_ACCESS set in her/his VM access.
userCaps
:=
vm
.
Access
[
loggedUserEmail
]
_
,
exists
:=
userCaps
[
caps
.
CAP_VM_SET_ACCESS
]
...
...
@@ -352,11 +363,6 @@ func (vms *VMs)DeleteVMAccess(vmID uuid.UUID, loggedUserEmail, userEmail string)
// Removes the user from the Access map
delete
(
vm
.
Access
,
userEmail
)
vm
.
mutex
.
Lock
()
defer
vm
.
mutex
.
Unlock
()
vms
.
rwlock
.
Lock
()
defer
vms
.
rwlock
.
Unlock
()
if
err
=
vms
.
updateVM
(
&
vm
);
err
!=
nil
{
return
errors
.
New
(
"Failed updating VM"
)
}
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment