mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-05-08 06:31:00 +08:00
239 lines
5.1 KiB
Go
239 lines
5.1 KiB
Go
// Copyright 2019 Yunion
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package sysutils
|
|
|
|
import (
|
|
"io/ioutil"
|
|
"os"
|
|
"path"
|
|
"regexp"
|
|
"strings"
|
|
|
|
"yunion.io/x/log"
|
|
"yunion.io/x/pkg/utils"
|
|
|
|
"yunion.io/x/onecloud/pkg/util/fileutils2"
|
|
"yunion.io/x/onecloud/pkg/util/procutils"
|
|
)
|
|
|
|
const (
|
|
KVM_MODULE_INTEL = "kvm-intel"
|
|
KVM_MODULE_AMD = "kvm-amd"
|
|
KVM_MODULE = "kvm"
|
|
KVM_MODULE_UNSUPPORT = "unsupport"
|
|
KVM_MODULE_BUILDIN = "buildin"
|
|
|
|
HOST_NEST_UNSUPPORT = "0"
|
|
HOST_NEST_SUPPORT = "1"
|
|
HOST_NEST_ENABLE = "3"
|
|
)
|
|
|
|
var (
|
|
kvmModuleSupport string
|
|
nestStatus string
|
|
)
|
|
|
|
func GetKVMModuleSupport() string {
|
|
if len(kvmModuleSupport) == 0 {
|
|
kvmModuleSupport = detectKVMModuleSupport()
|
|
}
|
|
return kvmModuleSupport
|
|
}
|
|
|
|
func IsKvmSupport() bool {
|
|
GetKVMModuleSupport()
|
|
if kvmModuleSupport == KVM_MODULE_UNSUPPORT {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
func IsProcessorIntel() bool {
|
|
GetKVMModuleSupport()
|
|
if kvmModuleSupport == KVM_MODULE_INTEL {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func IsProcessorAmd() bool {
|
|
GetKVMModuleSupport()
|
|
if kvmModuleSupport == KVM_MODULE_AMD {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func isDevKVMExists() bool {
|
|
return fileutils2.Exists("/dev/kvm")
|
|
}
|
|
|
|
func detectKVMModuleSupport() string {
|
|
var km = KVM_MODULE_UNSUPPORT
|
|
if ModprobeKvmModule(KVM_MODULE_INTEL, false, false) {
|
|
km = KVM_MODULE_INTEL
|
|
} else if ModprobeKvmModule(KVM_MODULE_AMD, false, false) {
|
|
km = KVM_MODULE_AMD
|
|
} else if ModprobeKvmModule(KVM_MODULE, false, false) {
|
|
if isDevKVMExists() {
|
|
km = KVM_MODULE
|
|
}
|
|
}
|
|
if km == KVM_MODULE_UNSUPPORT {
|
|
if isDevKVMExists() {
|
|
km = KVM_MODULE_BUILDIN
|
|
}
|
|
}
|
|
return km
|
|
}
|
|
|
|
func ModprobeKvmModule(name string, remove, nest bool) bool {
|
|
var params = []string{"modprobe"}
|
|
if remove {
|
|
params = append(params, "-r")
|
|
}
|
|
params = append(params, name)
|
|
if nest {
|
|
params = append(params, "nested=1")
|
|
}
|
|
if err := procutils.NewRemoteCommandAsFarAsPossible(params[0], params[1:]...).Run(); err != nil {
|
|
log.Errorf("Modprobe kvm %v failed: %s", params, err)
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
func IsNestEnabled() bool {
|
|
return GetNestSupport() == HOST_NEST_ENABLE
|
|
}
|
|
|
|
func GetNestSupport() string {
|
|
if len(nestStatus) == 0 {
|
|
nestStatus = detectNestSupport()
|
|
}
|
|
return nestStatus
|
|
}
|
|
|
|
func detectNestSupport() string {
|
|
moduleName := GetKVMModuleSupport()
|
|
nestStatus := HOST_NEST_UNSUPPORT
|
|
|
|
if moduleName != KVM_MODULE_UNSUPPORT && isNestSupport(moduleName) {
|
|
log.Infof("Host is support kvm nest ...")
|
|
nestStatus = HOST_NEST_SUPPORT
|
|
}
|
|
|
|
if nestStatus == HOST_NEST_SUPPORT && loadKvmModuleWithNest(moduleName) {
|
|
log.Infof("Host kvm nest is enabled ...")
|
|
nestStatus = HOST_NEST_ENABLE
|
|
}
|
|
return nestStatus
|
|
}
|
|
|
|
func isNestSupport(name string) bool {
|
|
output, err := procutils.NewRemoteCommandAsFarAsPossible("modinfo", name).Output()
|
|
if err != nil {
|
|
log.Errorln(err)
|
|
return false
|
|
}
|
|
|
|
// TODO Test
|
|
var re = regexp.MustCompile(`parm:\s*nested:`)
|
|
for _, line := range strings.Split(string(output), "\n") {
|
|
if re.MatchString(line) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func loadKvmModuleWithNest(name string) bool {
|
|
var notload = true
|
|
if IsKernelModuleLoaded(name) {
|
|
nest := GetKernelModuleParameter(name, "nested")
|
|
if nest == "Y" {
|
|
return true
|
|
}
|
|
notload = unloadKvmModule(name)
|
|
}
|
|
if notload {
|
|
if ModprobeKvmModule(name, false, true) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func unloadKvmModule(name string) bool {
|
|
return ModprobeKvmModule(name, true, false)
|
|
}
|
|
|
|
func GetKernelModuleParameter(name, moduel string) string {
|
|
pa := path.Join("/sys/module/", strings.Replace(name, "-", "_", -1), "/parameters/", moduel)
|
|
if f, err := os.Stat(pa); err == nil {
|
|
if f.IsDir() {
|
|
return ""
|
|
}
|
|
cont, err := fileutils2.FileGetContents(pa)
|
|
if err != nil {
|
|
log.Errorln(err)
|
|
return ""
|
|
}
|
|
return strings.TrimSpace(cont)
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func IsKernelModuleLoaded(name string) bool {
|
|
output, err := procutils.NewRemoteCommandAsFarAsPossible("lsmod").Output()
|
|
if err != nil {
|
|
log.Errorln(err)
|
|
return false
|
|
}
|
|
for _, line := range strings.Split(string(output), "\n") {
|
|
lm := strings.Split(line, " ")
|
|
if len(lm) > 0 && utils.IsInStringArray(strings.Replace(name, "-", "_", -1), lm) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func SetSysConfig(cpath, val string) bool {
|
|
if fileutils2.Exists(cpath) {
|
|
oval, err := ioutil.ReadFile(cpath)
|
|
if err != nil {
|
|
log.Errorln(err)
|
|
return false
|
|
}
|
|
if string(oval) != val {
|
|
err = fileutils2.FilePutContents(cpath, val, false)
|
|
if err == nil {
|
|
return true
|
|
}
|
|
log.Errorln(err)
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func IsHypervisor() bool {
|
|
cont, _ := fileutils2.FileGetContents("/proc/cpuinfo")
|
|
if strings.Index(cont, " hypervisor") > 0 {
|
|
return true
|
|
}
|
|
return false
|
|
}
|