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

Fixed bug where server complains about "Insufficient free RAM to start VM"...

Fixed bug where server complains about "Insufficient free RAM to start VM" despite enough RAM available
parent fdc10560
No related branches found
No related tags found
No related merge requests found
...@@ -11,4 +11,12 @@ const ( ...@@ -11,4 +11,12 @@ const (
VMSpiceMaxPort = 65000 VMSpiceMaxPort = 65000
MaxUploadSize = "30G" MaxUploadSize = "30G"
// We estimate that KVM allows for this amount of RAM saving in %
// (due to page sharing across VMs).
KsmRamSaving = 0.3
// To prevent RAM saturation, we refuse running new VMs if more than
// this amount of memory is being used (in %).
RamUsageLimit = .85
) )
...@@ -38,6 +38,7 @@ func (q *QGACon)SendShutdown() error { ...@@ -38,6 +38,7 @@ func (q *QGACon)SendShutdown() error {
return err return err
} }
// TODO: work in progress...
func (q *QGACon)WriteFile(filePath string) error { func (q *QGACon)WriteFile(filePath string) error {
filePath = "/home/nexus/pipo.txt" filePath = "/home/nexus/pipo.txt"
_, err := q.sock.Write([]byte(`{"execute":"guest-file-open", "arguments":{"path":"`+filePath+`","mode":"w+"}}`)) _, err := q.sock.Write([]byte(`{"execute":"guest-file-open", "arguments":{"path":"`+filePath+`","mode":"w+"}}`))
......
...@@ -23,7 +23,6 @@ func GetRAM() (int, int, error) { ...@@ -23,7 +23,6 @@ func GetRAM() (int, int, error) {
var memTotal int = -1 var memTotal int = -1
var memAvail int = -1 var memAvail int = -1
const units = 1024 const units = 1024
for scan.Scan() { for scan.Scan() {
......
...@@ -4,6 +4,7 @@ import ( ...@@ -4,6 +4,7 @@ import (
"os" "os"
"sort" "sort"
"sync" "sync"
"math"
"errors" "errors"
"path/filepath" "path/filepath"
"nexus-server/exec" "nexus-server/exec"
...@@ -23,6 +24,7 @@ type ( ...@@ -23,6 +24,7 @@ type (
dir string // Base directory where VMs are stored dir string // Base directory where VMs are stored
rwlock *sync.RWMutex // RWlock to ensure the coherency of the map (m) of VMs rwlock *sync.RWMutex // RWlock to ensure the coherency of the map (m) of VMs
usedPorts [65536]bool // Indicates which ports are used by the VMs usedPorts [65536]bool // Indicates which ports are used by the VMs
usedRAM int // Used RAM by running VMs (in MB)
} }
) )
...@@ -39,7 +41,7 @@ func GetVMsInstance() *VMs { ...@@ -39,7 +41,7 @@ func GetVMsInstance() *VMs {
// NOTE: path is the root directory where VMs reside. // NOTE: path is the root directory where VMs reside.
func InitVMs() error { func InitVMs() error {
vmsDir := paths.GetInstance().VMsDir vmsDir := paths.GetInstance().VMsDir
vms = &VMs { m: make(map[string]VM), dir: vmsDir, rwlock: new(sync.RWMutex) } vms = &VMs { m: make(map[string]VM), dir: vmsDir, rwlock: new(sync.RWMutex), usedRAM: 0 }
errMsg := "Failed reading VMs directory: " errMsg := "Failed reading VMs directory: "
dirs1, err := utils.GetSubDirs(vmsDir) dirs1, err := utils.GetSubDirs(vmsDir)
...@@ -170,18 +172,20 @@ func (vms *VMs)StartVM(vmID uuid.UUID) (int, string, error) { ...@@ -170,18 +172,20 @@ func (vms *VMs)StartVM(vmID uuid.UUID) (int, string, error) {
return 0, "", err return 0, "", err
} }
_, availRAM, err := utils.GetRAM() totalRAM, availRAM, err := utils.GetRAM()
if err != nil { if err != nil {
return -1, "", errors.New("Failed obtaining memory info: "+err.Error()) return -1, "", errors.New("Failed obtaining memory info: "+err.Error())
} }
// Check there will be at least 16GB of RAM left after the VM has started, // We estimate that KVM allows for ~30% RAM saving (due to page sharing across VMs).
// otherwise, we prevent the execution of the VM to avoid RAM saturation. estimatedVmRAM := int(math.Round(float64(vm.Ram)*(1.-consts.KsmRamSaving)))
// Thanks to Linux's KSVM technology, pages sharing the same content are actually shared
// which dramatically reduces the amount of RAM being used (roughly ~50% in average). vms.usedRAM += estimatedVmRAM
log.Info("vm.RAM: ", vm.Ram)
log.Info("Available RAM: ", availRAM) // Checks that at least 15% of the available RAM is left after the VM has started,
if availRAM - vm.Ram < 16*1024 { // otherwise, refuses to run it in order to avoid RAM saturation.
if availRAM - vms.usedRAM <= int(math.Round(float64(totalRAM)*(1.-consts.RamUsageLimit))) {
vms.usedRAM -= estimatedVmRAM
return -1, "", errors.New("Insufficient free RAM to start VM") return -1, "", errors.New("Insufficient free RAM to start VM")
} }
...@@ -205,6 +209,7 @@ func (vms *VMs)StartVM(vmID uuid.UUID) (int, string, error) { ...@@ -205,6 +209,7 @@ func (vms *VMs)StartVM(vmID uuid.UUID) (int, string, error) {
vm.mutex.Unlock() vm.mutex.Unlock()
vms.rwlock.Lock() vms.rwlock.Lock()
vms.usedPorts[vm.Run.Port] = false vms.usedPorts[vm.Run.Port] = false
vms.usedRAM -= estimatedVmRAM
vms.updateVMMap(vm) vms.updateVMMap(vm)
vms.rwlock.Unlock() vms.rwlock.Unlock()
} }
...@@ -213,6 +218,7 @@ func (vms *VMs)StartVM(vmID uuid.UUID) (int, string, error) { ...@@ -213,6 +218,7 @@ func (vms *VMs)StartVM(vmID uuid.UUID) (int, string, error) {
pwd, err := vm.start(port, endofExecFn) pwd, err := vm.start(port, endofExecFn)
vms.updateVMMap(&vm) vms.updateVMMap(&vm)
vm.mutex.Unlock() vm.mutex.Unlock()
return port, pwd, err return port, pwd, err
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment