177 lines
3.4 KiB
Go
177 lines
3.4 KiB
Go
package vm
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"strings"
|
|
"time"
|
|
|
|
"NanoKVM-Server/proto"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
log "github.com/sirupsen/logrus"
|
|
)
|
|
|
|
const (
|
|
SwapFile = "/swapfile"
|
|
InittabPath = "/etc/inittab"
|
|
TempInittab = "/etc/.inittab.tmp"
|
|
)
|
|
|
|
func (s *Service) GetSwap(c *gin.Context) {
|
|
var rsp proto.Response
|
|
|
|
rsp.OkRspWithData(c, &proto.GetSwapRsp{
|
|
Size: getSwapSize(),
|
|
})
|
|
}
|
|
|
|
func (s *Service) SetSwap(c *gin.Context) {
|
|
var rsp proto.Response
|
|
var req proto.SetSwapReq
|
|
|
|
if err := proto.ParseFormRequest(c, &req); err != nil {
|
|
rsp.ErrRsp(c, -1, "invalid arguments")
|
|
return
|
|
}
|
|
|
|
size := getSwapSize()
|
|
if req.Size == size {
|
|
rsp.OkRsp(c)
|
|
return
|
|
}
|
|
|
|
if req.Size == 0 {
|
|
if err := disableSwap(); err != nil {
|
|
rsp.ErrRsp(c, -2, "disable swap failed")
|
|
return
|
|
}
|
|
if err := disableInittab(); err != nil {
|
|
rsp.ErrRsp(c, -3, "disable inittab failed")
|
|
return
|
|
}
|
|
} else {
|
|
if err := enableSwap(req.Size); err != nil {
|
|
rsp.ErrRsp(c, -4, "enable swap failed")
|
|
return
|
|
}
|
|
if err := enableInittab(); err != nil {
|
|
rsp.ErrRsp(c, -5, "enable inittab failed")
|
|
return
|
|
}
|
|
}
|
|
|
|
rsp.OkRsp(c)
|
|
}
|
|
|
|
func getSwapSize() int64 {
|
|
fileInfo, err := os.Stat(SwapFile)
|
|
if err != nil {
|
|
return 0
|
|
}
|
|
|
|
return fileInfo.Size() / 1024 / 1024
|
|
}
|
|
|
|
func enableSwap(size int64) error {
|
|
if getSwapSize() > 0 {
|
|
if err := disableSwap(); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
commands := []string{
|
|
fmt.Sprintf("fallocate -l %dM %s", size, SwapFile),
|
|
fmt.Sprintf("chmod 600 %s", SwapFile),
|
|
fmt.Sprintf("mkswap %s", SwapFile),
|
|
fmt.Sprintf("swapon %s", SwapFile),
|
|
}
|
|
|
|
for _, command := range commands {
|
|
err := exec.Command("sh", "-c", command).Run()
|
|
if err != nil {
|
|
log.Errorf("failed to execute %s: %s", command, err)
|
|
return err
|
|
}
|
|
|
|
time.Sleep(300 * time.Millisecond)
|
|
}
|
|
|
|
log.Debugf("set swap file size: %d", size)
|
|
return nil
|
|
}
|
|
|
|
func disableSwap() error {
|
|
command := "swapoff -a"
|
|
if err := exec.Command("sh", "-c", command).Run(); err != nil {
|
|
log.Errorf("failed to execute swapoff: %s", err)
|
|
return err
|
|
}
|
|
|
|
if err := os.Remove(SwapFile); err != nil {
|
|
log.Errorf("failed to delete %s: %s", SwapFile, err)
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func enableInittab() error {
|
|
f, err := os.OpenFile(InittabPath, os.O_APPEND|os.O_WRONLY, 0644)
|
|
if err != nil {
|
|
log.Errorf("read inittab failed: %s", err)
|
|
return err
|
|
}
|
|
defer func() {
|
|
_ = f.Close()
|
|
}()
|
|
|
|
content := fmt.Sprintf("\nsi11::sysinit:/sbin/swapon %s", SwapFile)
|
|
_, err = f.WriteString(content)
|
|
if err != nil {
|
|
log.Errorf("write inittab failed: %s", err)
|
|
return err
|
|
}
|
|
|
|
log.Debugf("write to %s: %s", InittabPath, content)
|
|
return nil
|
|
}
|
|
|
|
func disableInittab() error {
|
|
defer func() {
|
|
_ = os.Remove(TempInittab)
|
|
}()
|
|
|
|
input, err := os.ReadFile(InittabPath)
|
|
if err != nil {
|
|
log.Errorf("read fstab failed: %s", err)
|
|
return err
|
|
}
|
|
|
|
lines := strings.Split(string(input), "\n")
|
|
output := make([]string, 0)
|
|
|
|
for _, line := range lines {
|
|
if strings.HasSuffix(line, SwapFile) {
|
|
log.Debugf("%s delete line: %s", InittabPath, line)
|
|
} else {
|
|
output = append(output, line)
|
|
}
|
|
}
|
|
|
|
content := strings.Join(output, "\n")
|
|
content = strings.TrimSuffix(content, "\n")
|
|
if err := os.WriteFile(TempInittab, []byte(content), 0644); err != nil {
|
|
log.Errorf("write temp fstab failed: %s", err)
|
|
return err
|
|
}
|
|
|
|
if err := os.Rename(TempInittab, InittabPath); err != nil {
|
|
log.Errorf("replace fstab failed: %s", err)
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|