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

Ongoing work on fixing "Insufficient free RAM to start VM" issue

parent b9f2f735
No related branches found
No related tags found
No related merge requests found
...@@ -3,6 +3,7 @@ package qga ...@@ -3,6 +3,7 @@ package qga
import ( import (
"fmt" "fmt"
"net" "net"
"errors"
"encoding/base64" "encoding/base64"
"nexus-server/logger" "nexus-server/logger"
) )
...@@ -38,7 +39,7 @@ func (q *QGACon)SendShutdown() error { ...@@ -38,7 +39,7 @@ func (q *QGACon)SendShutdown() error {
} }
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+"}}`))
buf := make([]byte, 128) buf := make([]byte, 128)
_, err = q.sock.Read(buf) _, err = q.sock.Read(buf)
...@@ -51,7 +52,10 @@ func (q *QGACon)WriteFile(filePath string) error { ...@@ -51,7 +52,10 @@ func (q *QGACon)WriteFile(filePath string) error {
// content must be encoded in base64 // content must be encoded in base64
content := "Hello ma poule!" content := "Hello ma poule!"
contentB64 := base64.StdEncoding.EncodeToString([]byte(content)) contentB64 := base64.StdEncoding.EncodeToString([]byte(content))
status, err = q.sock.Write([]byte(`{"execute":"guest-file-write", "arguments":{"handle":1000,"buf-b64":"`+contentB64+`"}}`)) status, err := q.sock.Write([]byte(`{"execute":"guest-file-write", "arguments":{"handle":1000,"buf-b64":"`+contentB64+`"}}`))
status, err = q.sock.Write([]byte(`{"execute":"guest-file-close", "arguments":{"handle":1000}}`)) status, err = q.sock.Write([]byte(`{"execute":"guest-file-close", "arguments":{"handle":1000}}`))
if status < 0 {
return errors.New("write error")
}
return err return err
} }
...@@ -2,7 +2,6 @@ package vms ...@@ -2,7 +2,6 @@ package vms
import ( import (
"os" "os"
"math"
"sort" "sort"
"sync" "sync"
"errors" "errors"
...@@ -24,7 +23,6 @@ type ( ...@@ -24,7 +23,6 @@ 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)
} }
) )
...@@ -41,7 +39,7 @@ func GetVMsInstance() *VMs { ...@@ -41,7 +39,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), usedRAM: 0 } vms = &VMs { m: make(map[string]VM), dir: vmsDir, rwlock: new(sync.RWMutex) }
errMsg := "Failed reading VMs directory: " errMsg := "Failed reading VMs directory: "
dirs1, err := utils.GetSubDirs(vmsDir) dirs1, err := utils.GetSubDirs(vmsDir)
...@@ -172,18 +170,18 @@ func (vms *VMs)StartVM(vmID uuid.UUID) (int, string, error) { ...@@ -172,18 +170,18 @@ func (vms *VMs)StartVM(vmID uuid.UUID) (int, string, error) {
return 0, "", err return 0, "", err
} }
// Check there will be at least 2GB of RAM left after the VM has started,
// otherwise, we prevent the execution of the VM to avoid RAM saturation.
// Furthermore, given Linux's KSVM technology allows page sharing, we
// assume it's able to save 30% of RAM (should be a conservative estimate).
_, availRAM, err := utils.GetRAM() _, 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())
} }
vms.usedRAM += vm.Ram // Check there will be at least 16GB of RAM left after the VM has started,
if availRAM - int(math.Round(float64(vms.usedRAM)*0.7)) < 2048 { // otherwise, we prevent the execution of the VM to avoid RAM saturation.
vms.usedRAM -= vm.Ram // 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).
log.Info("vm.RAM: ", vm.Ram)
log.Info("Available RAM: ", availRAM)
if availRAM - vm.Ram < 16*1024 {
return -1, "", errors.New("Insufficient free RAM to start VM") return -1, "", errors.New("Insufficient free RAM to start VM")
} }
...@@ -207,7 +205,6 @@ func (vms *VMs)StartVM(vmID uuid.UUID) (int, string, error) { ...@@ -207,7 +205,6 @@ 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 -= vm.Ram
vms.updateVMMap(vm) vms.updateVMMap(vm)
vms.rwlock.Unlock() vms.rwlock.Unlock()
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment