From 3d4766611cebbf78cb4f0aa8a445574ab443e1bb Mon Sep 17 00:00:00 2001 From: Jian Qiu Date: Mon, 15 Apr 2019 16:11:10 +0800 Subject: [PATCH] Feature: host support centos 6 (#406) --- pkg/compute/models/disks.go | 6 +- pkg/hostman/guestman/qemu-kvmhelper.go | 13 +- pkg/hostman/hostinfo/hostinfo.go | 183 +++--------------- pkg/hostman/options/options.go | 2 + .../storageman/imagecachemanager_local.go | 4 +- pkg/hostman/system_service/docker.go | 2 +- pkg/hostman/system_service/fluentbit.go | 2 +- pkg/hostman/system_service/kube_agent.go | 2 +- pkg/hostman/system_service/lxcfs.go | 2 +- pkg/hostman/system_service/ntpd.go | 2 +- pkg/hostman/system_service/openvswitch.go | 2 +- pkg/hostman/system_service/sdnagent.go | 2 +- pkg/hostman/system_service/servicemanager.go | 15 ++ pkg/hostman/system_service/system_service.go | 64 +++--- pkg/hostman/system_service/systemd.go | 66 +++++++ pkg/hostman/system_service/systemd_test.go | 32 +++ pkg/hostman/system_service/sysv.go | 61 ++++++ pkg/hostman/system_service/sysv_test.go | 25 +++ pkg/hostman/system_service/telegraf.go | 2 +- pkg/util/fileutils2/fileutils.go | 8 + pkg/util/sysutils/hostname.go | 30 +++ pkg/util/sysutils/kvm.go | 179 +++++++++++++++++ 22 files changed, 491 insertions(+), 213 deletions(-) create mode 100644 pkg/hostman/system_service/servicemanager.go create mode 100644 pkg/hostman/system_service/systemd.go create mode 100644 pkg/hostman/system_service/systemd_test.go create mode 100644 pkg/hostman/system_service/sysv.go create mode 100644 pkg/hostman/system_service/sysv_test.go create mode 100644 pkg/util/sysutils/hostname.go create mode 100644 pkg/util/sysutils/kvm.go diff --git a/pkg/compute/models/disks.go b/pkg/compute/models/disks.go index 3f4a2ce937..6cdfa7d64d 100644 --- a/pkg/compute/models/disks.go +++ b/pkg/compute/models/disks.go @@ -1245,9 +1245,9 @@ func fillDiskConfigByImage(ctx context.Context, userCred mcclient.TokenCredentia } diskConfig.ImageId = image.Id diskConfig.ImageProperties = image.Properties - if len(diskConfig.Format) == 0 { - diskConfig.Format = image.DiskFormat - } + // if len(diskConfig.Format) == 0 { + // diskConfig.Format = image.DiskFormat + // } // diskConfig.ImageDiskFormat = image.DiskFormat CachedimageManager.ImageAddRefCount(image.Id) if diskConfig.SizeMb < image.MinDiskMB { diff --git a/pkg/hostman/guestman/qemu-kvmhelper.go b/pkg/hostman/guestman/qemu-kvmhelper.go index 8457ec2279..c882fd6825 100644 --- a/pkg/hostman/guestman/qemu-kvmhelper.go +++ b/pkg/hostman/guestman/qemu-kvmhelper.go @@ -30,6 +30,7 @@ import ( "yunion.io/x/onecloud/pkg/util/ethernet/arp" "yunion.io/x/onecloud/pkg/util/fileutils2" "yunion.io/x/onecloud/pkg/util/qemutils" + "yunion.io/x/onecloud/pkg/util/sysutils" ) const ( @@ -383,8 +384,18 @@ func (s *SKVMGuestInstance) generateStartScript(data *jsonutils.JSONDict) (strin cpuType = "" if osname == OS_NAME_MACOS { cpuType = "Penryn,vendor=GenuineIntel" - } else { + } else if options.HostOptions.HostCpuPassthrough { cpuType = "host" + } else { + cpuType = "qemu64" + if sysutils.IsProcessorIntel() { + cpuType += ",+vmx" + cpuType += ",+ssse3,+sse4.1,+sse4.2,-x2apic,+aes,+avx" + cpuType += ",+vme,+pat,+ss,+pclmulqdq,+xsave" + cpuType += ",level=13" + } else if sysutils.IsProcessorAmd() { + cpuType += ",+svm" + } } if !guestManger.GetHost().IsNestedVirtualization() { diff --git a/pkg/hostman/hostinfo/hostinfo.go b/pkg/hostman/hostinfo/hostinfo.go index fb47de11ff..13c14f8ce2 100644 --- a/pkg/hostman/hostinfo/hostinfo.go +++ b/pkg/hostman/hostinfo/hostinfo.go @@ -51,16 +51,6 @@ import ( "yunion.io/x/onecloud/pkg/util/winutils" ) -var ( - KVM_MODULE_INTEL = "kvm-intel" - KVM_MODULE_AMD = "kvm-amd" - KVM_MODULE_UNSUPPORT = "unsupport" - - HOST_NEST_UNSUPPORT = "0" - HOST_NEST_SUPPORT = "1" - HOST_NEST_ENABLE = "3" -) - type SHostInfo struct { isRegistered bool IsRegistered chan struct{} @@ -70,9 +60,6 @@ type SHostInfo struct { saved bool pinger *SHostPingTask - kvmModuleSupport string - nestStatus string - Cpu *SCPUInfo Mem *SMemory sysinfo *SSysInfo @@ -121,10 +108,7 @@ func (h *SHostInfo) GetMediumType() string { } func (h *SHostInfo) IsKvmSupport() bool { - if h.kvmModuleSupport == KVM_MODULE_UNSUPPORT { - return false - } - return true + return sysutils.IsKvmSupport() } func (h *SHostInfo) IsNestedVirtualization() bool { @@ -290,9 +274,8 @@ func (h *SHostInfo) detectHostInfo() error { } h.sysinfo.SDMISystemInfo = sysinfo - h.detectiveKVMModuleSupport() - h.detectiveNestSupport() - h.tryEnableNest() + h.detectKvmModuleSupport() + h.detectNestSupport() if err := h.detectiveSyssoftwareInfo(); err != nil { return err @@ -458,149 +441,18 @@ func (h *SHostInfo) resetIptables() error { return nil } -func (h *SHostInfo) detectiveKVMModuleSupport() { - if len(h.kvmModuleSupport) == 0 { - h.kvmModuleSupport = h._detectiveKVMModuleSupport() - } +func (h *SHostInfo) detectKvmModuleSupport() string { + return sysutils.GetKVMModuleSupport() } -func (h *SHostInfo) _detectiveKVMModuleSupport() string { - var km = KVM_MODULE_UNSUPPORT - if h.modprobeKvmModule(KVM_MODULE_INTEL, false, false) { - km = KVM_MODULE_INTEL - } else if h.modprobeKvmModule(KVM_MODULE_AMD, false, false) { - km = KVM_MODULE_AMD - } - return km -} - -func (h *SHostInfo) 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.NewCommand(params[0], params[1:]...).Run(); err != nil { - return false - } - return true -} - -func (h *SHostInfo) getKvmModuleSupport() string { - if len(h.kvmModuleSupport) == 0 { - h.detectiveKVMModuleSupport() - } - return h.kvmModuleSupport -} - -func (h *SHostInfo) detectiveNestSupport() { - if len(h.nestStatus) == 0 { - h.nestStatus = h._detectiveNestSupport() - } - h.sysinfo.Nest = h.nestStatus2Str(h.nestStatus) -} - -func (h *SHostInfo) _detectiveNestSupport() string { - var ( - moduleName = h.getKvmModuleSupport() - nestStatus = HOST_NEST_UNSUPPORT - ) - - if moduleName != KVM_MODULE_UNSUPPORT && h._isNestSupport(moduleName) { - nestStatus = HOST_NEST_SUPPORT - } - return nestStatus -} - -func (h *SHostInfo) _isNestSupport(name string) bool { - output, err := procutils.NewCommand("modinfo", name).Run() - 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 (h *SHostInfo) nestStatus2Str(status string) string { - if status == HOST_NEST_ENABLE { - return "enabled" +func (h *SHostInfo) detectNestSupport() { + if sysutils.IsNestEnabled() { + h.sysinfo.Nest = "enabled" } else { - return "disbaled" + h.sysinfo.Nest = "disabled" } } -func (h *SHostInfo) tryEnableNest() { - if h.nestStatus == HOST_NEST_SUPPORT { - if h.loadKvmModuleWithNest(h.kvmModuleSupport) { - h.nestStatus = HOST_NEST_ENABLE - } - } - h.sysinfo.Nest = h.nestStatus2Str(h.nestStatus) -} - -func (h *SHostInfo) loadKvmModuleWithNest(name string) bool { - var notload = true - if h.checkKvmModuleInstall(name) { - nest := h.getModuleParameter(name, "nested") - if nest == "Y" { - return true - } - notload = h.unloadKvmModule(name) - } - if notload { - if h.modprobeKvmModule(name, false, true) { - return true - } - } - return false -} - -func (h *SHostInfo) unloadKvmModule(name string) bool { - return h.modprobeKvmModule(name, true, false) -} - -func (h *SHostInfo) getModuleParameter(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 (h *SHostInfo) checkKvmModuleInstall(name string) bool { - output, err := procutils.NewCommand("lsmod").Run() - 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 (h *SHostInfo) detectiveOsDist() { files, err := procutils.NewCommand("sh", "-c", "ls /etc/*elease").Run() if err != nil { @@ -819,7 +671,7 @@ func (h *SHostInfo) getHostInfo(zoneId string) { func (h *SHostInfo) setHostname(name string) { h.FullName = name - _, err := procutils.NewCommand("hostnamectl", "set-hostname", name).Run() + err := sysutils.SetHostname(name) if err != nil { log.Errorln("Fail to set system hostname: %s", err) } @@ -829,8 +681,21 @@ func (h *SHostInfo) fetchHostname() string { if len(options.HostOptions.Hostname) > 0 { return options.HostOptions.Hostname } else { + hn, err := os.Hostname() + if err != nil { + log.Fatalf("fail to get hostname %s", err) + return "" + } + dotIdx := strings.IndexByte(hn, '.') + if dotIdx >= 0 { + hn = hn[:dotIdx] + } + hn = strings.ToLower(hn) + if len(hn) == 0 { + hn = "host" + } masterIp := h.GetMasterIp() - return "host-" + masterIp + return hn + "-" + strings.Replace(masterIp, ".", "-", -1) } } diff --git a/pkg/hostman/options/options.go b/pkg/hostman/options/options.go index 7bd4bf4c07..58fb49c013 100644 --- a/pkg/hostman/options/options.go +++ b/pkg/hostman/options/options.go @@ -100,6 +100,8 @@ type SHostOptions struct { EnableTelegraf bool `default:"true" help:"enable send monitoring data to telegraf"` WindowsDefaultAdminUser bool `default:"true" help:"Default account for Windows system is Administrator"` + + HostCpuPassthrough bool `default:"true" help:"if it is true, set qemu cpu type as -cpu host, otherwise, qemu64. default is true"` } var HostOptions SHostOptions diff --git a/pkg/hostman/storageman/imagecachemanager_local.go b/pkg/hostman/storageman/imagecachemanager_local.go index fc6c144173..971bab8279 100644 --- a/pkg/hostman/storageman/imagecachemanager_local.go +++ b/pkg/hostman/storageman/imagecachemanager_local.go @@ -127,7 +127,9 @@ func (c *SLocalImageCacheManager) PrefetchImageCache(ctx context.Context, data i if err != nil { return nil, err } - format, _ := body.GetString("format") + // format, _ := body.GetString("format") + // force qcow2 for KVM + format := "qcow2" srcUrl, _ := body.GetString("src_url") if imgCache := c.AcquireImage(ctx, imageId, storageManager.GetZone(), diff --git a/pkg/hostman/system_service/docker.go b/pkg/hostman/system_service/docker.go index 29abb3f8a6..df9ed0c439 100644 --- a/pkg/hostman/system_service/docker.go +++ b/pkg/hostman/system_service/docker.go @@ -25,7 +25,7 @@ type SDocker struct { } func NewDockerService() *SDocker { - return &SDocker{&SBaseSystemService{"docker", nil}} + return &SDocker{NewBaseSystemService("docker", nil)} } func (s *SDocker) GetConfig(kwargs map[string]interface{}) string { diff --git a/pkg/hostman/system_service/fluentbit.go b/pkg/hostman/system_service/fluentbit.go index 3a2a2bcdec..a41de92c6b 100644 --- a/pkg/hostman/system_service/fluentbit.go +++ b/pkg/hostman/system_service/fluentbit.go @@ -29,7 +29,7 @@ type SFluentbit struct { } func NewFluentbitService() *SFluentbit { - return &SFluentbit{&SBaseSystemService{"fluentbit", nil}} + return &SFluentbit{NewBaseSystemService("fluentbit", nil)} } func (s *SFluentbit) GetConfig(kwargs map[string]interface{}) string { diff --git a/pkg/hostman/system_service/kube_agent.go b/pkg/hostman/system_service/kube_agent.go index 268cdc6e1d..068a1a6508 100644 --- a/pkg/hostman/system_service/kube_agent.go +++ b/pkg/hostman/system_service/kube_agent.go @@ -21,7 +21,7 @@ type SKubeAgent struct { } func NewKubeAgentService() *SKubeAgent { - return &SKubeAgent{&SBaseSystemService{"yunion-kube-agent", nil}} + return &SKubeAgent{NewBaseSystemService("yunion-kube-agent", nil)} } func (s *SKubeAgent) GetConfig(kwargs map[string]interface{}) string { diff --git a/pkg/hostman/system_service/lxcfs.go b/pkg/hostman/system_service/lxcfs.go index 29a4f95297..4e6410ca71 100644 --- a/pkg/hostman/system_service/lxcfs.go +++ b/pkg/hostman/system_service/lxcfs.go @@ -19,7 +19,7 @@ type SLxcfs struct { } func NewLxcfsService() *SLxcfs { - return &SLxcfs{&SBaseSystemService{"lxcfs", nil}} + return &SLxcfs{NewBaseSystemService("lxcfs", nil)} } func (s *SLxcfs) Reload(kwargs map[string]interface{}) error { diff --git a/pkg/hostman/system_service/ntpd.go b/pkg/hostman/system_service/ntpd.go index c657df5700..e447dfd950 100644 --- a/pkg/hostman/system_service/ntpd.go +++ b/pkg/hostman/system_service/ntpd.go @@ -21,7 +21,7 @@ type SNtpd struct { } func NewNtpdService() *SNtpd { - return &SNtpd{&SBaseSystemService{"ntpd", nil}} + return &SNtpd{NewBaseSystemService("ntpd", nil)} } func (s *SNtpd) GetConfig(kwargs map[string]interface{}) string { diff --git a/pkg/hostman/system_service/openvswitch.go b/pkg/hostman/system_service/openvswitch.go index f3e28952e6..abddec3779 100644 --- a/pkg/hostman/system_service/openvswitch.go +++ b/pkg/hostman/system_service/openvswitch.go @@ -19,7 +19,7 @@ type SOpenvswitch struct { } func NewOpenvswitchService() *SOpenvswitch { - return &SOpenvswitch{&SBaseSystemService{"openvswitch", nil}} + return &SOpenvswitch{NewBaseSystemService("openvswitch", nil)} } func (s *SOpenvswitch) Reload(kwargs map[string]interface{}) error { diff --git a/pkg/hostman/system_service/sdnagent.go b/pkg/hostman/system_service/sdnagent.go index a0ee192098..65aa2a8212 100644 --- a/pkg/hostman/system_service/sdnagent.go +++ b/pkg/hostman/system_service/sdnagent.go @@ -19,7 +19,7 @@ type SHostSdnagent struct { } func NewHostSdnagentService() *SHostSdnagent { - return &SHostSdnagent{&SBaseSystemService{"yunion-host-sdnagent", nil}} + return &SHostSdnagent{NewBaseSystemService("yunion-host-sdnagent", nil)} } func (s *SHostSdnagent) Reload(kwargs map[string]interface{}) error { diff --git a/pkg/hostman/system_service/servicemanager.go b/pkg/hostman/system_service/servicemanager.go new file mode 100644 index 0000000000..01f3685f45 --- /dev/null +++ b/pkg/hostman/system_service/servicemanager.go @@ -0,0 +1,15 @@ +package system_service + +type SServiceStatus struct { + Loaded bool + Active bool +} + +type IServiceManager interface { + Detect() bool + Start(srvname string) error + Enable(srvname string) error + Stop(srvname string) error + Disable(srvname string) error + GetStatus(srvname string) SServiceStatus +} diff --git a/pkg/hostman/system_service/system_service.go b/pkg/hostman/system_service/system_service.go index 96439e4b8c..e10fc6440f 100644 --- a/pkg/hostman/system_service/system_service.go +++ b/pkg/hostman/system_service/system_service.go @@ -15,12 +15,9 @@ package system_service import ( - "strings" - "yunion.io/x/log" "yunion.io/x/onecloud/pkg/util/fileutils2" - "yunion.io/x/onecloud/pkg/util/procutils" ) type ISystemService interface { @@ -34,7 +31,6 @@ type ISystemService interface { BgReload(kwargs map[string]interface{}) Enable() error Disable() error - GetStatus() map[string]string Reload(kwargs map[string]interface{}) error } @@ -60,8 +56,21 @@ func GetService(name string) ISystemService { } type SBaseSystemService struct { - name string - urls interface{} + manager IServiceManager + name string + urls interface{} +} + +func NewBaseSystemService(name string, urls interface{}) *SBaseSystemService { + ss := SBaseSystemService{} + if SysVServiceManager.Detect() { + ss.manager = SysVServiceManager + } else { + ss.manager = SystemdServiceManager + } + ss.name = name + ss.urls = urls + return &ss } func (s *SBaseSystemService) reload(conf, conFile string) error { @@ -81,28 +90,8 @@ func (s *SBaseSystemService) reload(conf, conFile string) error { } func (s *SBaseSystemService) IsInstalled() bool { - status := s.GetStatus() - if loaded, ok := status["loaded"]; ok && loaded == "loaded" { - return true - } - return false -} - -func (s *SBaseSystemService) GetStatus() map[string]string { - res, _ := procutils.NewCommand("systemctl", "status", s.name).Run() - var ret = make(map[string]string, 0) - lines := strings.Split(string(res), "\n") - for _, line := range lines { - line = strings.TrimSpace(line) - if len(line) > 0 { - if strings.HasPrefix(line, "Loaded:") { - ret["loaded"] = strings.Split(line, " ")[1] - } else if strings.HasPrefix(line, "Active:") { - ret["active"] = strings.Split(line, " ")[1] - } - } - } - return ret + status := s.manager.GetStatus(s.name) + return status.Loaded } func (s *SBaseSystemService) Start(enable bool) error { @@ -111,8 +100,7 @@ func (s *SBaseSystemService) Start(enable bool) error { return err } } - _, err := procutils.NewCommand("systemctl", "restart", s.name).Run() - return err + return s.manager.Start(s.name) } func (s *SBaseSystemService) Stop(disable bool) error { @@ -121,16 +109,12 @@ func (s *SBaseSystemService) Stop(disable bool) error { return err } } - _, err := procutils.NewCommand("systemctl", "stop", s.name).Run() - return err + return s.manager.Stop(s.name) } func (s *SBaseSystemService) IsActive() bool { - status := s.GetStatus() - if active, ok := status["active"]; ok && active == "active" { - return true - } - return false + status := s.manager.GetStatus(s.name) + return status.Active } func (s *SBaseSystemService) GetConfig(map[string]interface{}) string { @@ -150,11 +134,9 @@ func (s *SBaseSystemService) GetConf() interface{} { } func (s *SBaseSystemService) Enable() error { - _, err := procutils.NewCommand("systemctl", "enable", s.name).Run() - return err + return s.manager.Enable(s.name) } func (s *SBaseSystemService) Disable() error { - _, err := procutils.NewCommand("systemctl", "disable", s.name).Run() - return err + return s.manager.Disable(s.name) } diff --git a/pkg/hostman/system_service/systemd.go b/pkg/hostman/system_service/systemd.go new file mode 100644 index 0000000000..30d8a58115 --- /dev/null +++ b/pkg/hostman/system_service/systemd.go @@ -0,0 +1,66 @@ +package system_service + +import ( + "strings" + + "yunion.io/x/onecloud/pkg/util/procutils" +) + +var ( + SystemdServiceManager IServiceManager = &SSystemdServiceManager{} +) + +type SSystemdServiceManager struct { +} + +func (manager *SSystemdServiceManager) Detect() bool { + _, err := procutils.NewCommand("systemctl", "--version").Run() + return err == nil +} + +func (manager *SSystemdServiceManager) Start(srvname string) error { + _, err := procutils.NewCommand("systemctl", "restart", srvname).Run() + return err +} + +func (manager *SSystemdServiceManager) Enable(srvname string) error { + _, err := procutils.NewCommand("systemctl", "enable", srvname).Run() + return err +} + +func (manager *SSystemdServiceManager) Stop(srvname string) error { + _, err := procutils.NewCommand("systemctl", "stop", srvname).Run() + return err +} + +func (manager *SSystemdServiceManager) Disable(srvname string) error { + _, err := procutils.NewCommand("systemctl", "disable", srvname).Run() + return err +} + +func (manager *SSystemdServiceManager) GetStatus(srvname string) SServiceStatus { + res, _ := procutils.NewCommand("systemctl", "status", srvname).Run() + return parseSystemdStatus(string(res), srvname) +} + +func parseSystemdStatus(res string, srvname string) SServiceStatus { + var ret SServiceStatus + lines := strings.Split(string(res), "\n") + for _, line := range lines { + line = strings.TrimSpace(line) + if len(line) > 0 { + if strings.HasPrefix(line, "Loaded:") { + parts := strings.Split(line, " ") + if len(parts) > 1 && parts[1] == "loaded" { + ret.Loaded = true + } + } else if strings.HasPrefix(line, "Active:") { + parts := strings.Split(line, " ") + if len(parts) > 1 && parts[1] == "active" { + ret.Active = true + } + } + } + } + return ret +} diff --git a/pkg/hostman/system_service/systemd_test.go b/pkg/hostman/system_service/systemd_test.go new file mode 100644 index 0000000000..fc5b75a946 --- /dev/null +++ b/pkg/hostman/system_service/systemd_test.go @@ -0,0 +1,32 @@ +package system_service + +import ( + "testing" +) + +func TestParseSystemd(t *testing.T) { + cases := []struct { + in string + name string + wantLoaded bool + wantActive bool + }{ + {`openvswitch.service - LSB: Open vSwitch switch + Loaded: loaded (/etc/rc.d/init.d/openvswitch; bad; vendor preset: disabled) + Active: active (running) since Wed 2019-04-10 15:11:23 CST; 4 days ago + Docs: man:systemd-sysv-generator(8) + Process: 3686 ExecStart=/etc/rc.d/init.d/openvswitch start (code=exited, status=0/SUCCESS) + CGroup: /system.slice/openvswitch.service + ├─3722 ovsdb-server: monitoring pid 3723 (healthy) + ├─3723 ovsdb-server /etc/openvswitch/conf.db -vconsole:emer -vsysl... + ├─3774 ovs-vswitchd: monitoring pid 3775 (healthy) + └─3775 ovs-vswitchd unix:/var/run/openvswitch/db.sock -vconsole:em...`, "openvswitch", true, true}, + {"Unit yunion-host.service could not be found.", "yunion-host", false, false}, + } + for _, c := range cases { + status := parseSystemdStatus(c.in, c.name) + if status.Loaded != c.wantLoaded || status.Active != c.wantActive { + t.Errorf("parseSystemdStatus %s Loaded: want %v got %v Active: want %v got %v", c.name, c.wantLoaded, status.Loaded, c.wantActive, status.Active) + } + } +} diff --git a/pkg/hostman/system_service/sysv.go b/pkg/hostman/system_service/sysv.go new file mode 100644 index 0000000000..54e76d2c5b --- /dev/null +++ b/pkg/hostman/system_service/sysv.go @@ -0,0 +1,61 @@ +package system_service + +import ( + "strings" + + "yunion.io/x/onecloud/pkg/util/procutils" +) + +var ( + SysVServiceManager IServiceManager = &SSysVServiceManager{} +) + +type SSysVServiceManager struct { +} + +func (manager *SSysVServiceManager) Detect() bool { + _, err := procutils.NewCommand("chkconfig", "--version").Run() + return err == nil +} + +func (manager *SSysVServiceManager) Start(srvname string) error { + _, err := procutils.NewCommand("service", srvname, "restart").Run() + return err +} + +func (manager *SSysVServiceManager) Enable(srvname string) error { + _, err := procutils.NewCommand("chkconfig", srvname, "on").Run() + return err +} + +func (manager *SSysVServiceManager) Stop(srvname string) error { + _, err := procutils.NewCommand("service", srvname, "stop").Run() + return err +} + +func (manager *SSysVServiceManager) Disable(srvname string) error { + _, err := procutils.NewCommand("chkconfig", srvname, "off").Run() + return err +} + +func (manager *SSysVServiceManager) GetStatus(srvname string) SServiceStatus { + res, _ := procutils.NewCommand("chkconfig", "--list", srvname).Run() + res2, _ := procutils.NewCommand("service", srvname, "status").Run() + return parseSysvStatus(string(res), string(res2), srvname) +} + +func parseSysvStatus(res string, res2 string, srvname string) SServiceStatus { + var ret SServiceStatus + lines := strings.Split(res, "\n") + for _, line := range lines { + parts := strings.Split(strings.TrimSpace(line), "\t") + if len(parts) > 1 && strings.TrimSpace(parts[0]) == srvname { + ret.Loaded = true + if strings.Index(res2, "running") > 0 { + ret.Active = true + } + break + } + } + return ret +} diff --git a/pkg/hostman/system_service/sysv_test.go b/pkg/hostman/system_service/sysv_test.go new file mode 100644 index 0000000000..e171d82ffe --- /dev/null +++ b/pkg/hostman/system_service/sysv_test.go @@ -0,0 +1,25 @@ +package system_service + +import ( + "testing" +) + +func TestParseSysv(t *testing.T) { + cases := []struct { + in1 string + in2 string + name string + wantLoaded bool + wantActive bool + }{ + {`openvswitch 0:off 1:off 2:off 3:off 4:off 5:off 6:off`, `ovsdb-server is running with pid 114553 +ovs-vswitchd is running with pid 114563`, "openvswitch", true, true}, + {`yunion-host 0:off 1:off 2:on 3:on 4:on 5:on 6:off`, "", "yunion-host", true, false}, + } + for _, c := range cases { + status := parseSysvStatus(c.in1, c.in2, c.name) + if status.Loaded != c.wantLoaded || status.Active != c.wantActive { + t.Errorf("parseSysVStatus %s Loaded want %v got %v Active want %v got %v", c.name, c.wantLoaded, status.Loaded, c.wantActive, status.Active) + } + } +} diff --git a/pkg/hostman/system_service/telegraf.go b/pkg/hostman/system_service/telegraf.go index 04be5a0a35..a8c7cdd22e 100644 --- a/pkg/hostman/system_service/telegraf.go +++ b/pkg/hostman/system_service/telegraf.go @@ -24,7 +24,7 @@ type STelegraf struct { } func NewTelegrafService() *STelegraf { - return &STelegraf{&SBaseSystemService{"telegraf", nil}} + return &STelegraf{NewBaseSystemService("telegraf", nil)} } func (s *STelegraf) GetConfig(kwargs map[string]interface{}) string { diff --git a/pkg/util/fileutils2/fileutils.go b/pkg/util/fileutils2/fileutils.go index d48fda2d12..0be611fbfd 100644 --- a/pkg/util/fileutils2/fileutils.go +++ b/pkg/util/fileutils2/fileutils.go @@ -97,6 +97,14 @@ func Zerofiles(sPath string) error { return nil } +func FileSetContents(filename string, content string) error { + return FilePutContents(filename, content, false) +} + +func FileAppendContents(filename string, content string) error { + return FilePutContents(filename, content, true) +} + func FilePutContents(filename string, content string, modAppend bool) error { var mode = os.O_WRONLY | os.O_CREATE if modAppend { diff --git a/pkg/util/sysutils/hostname.go b/pkg/util/sysutils/hostname.go new file mode 100644 index 0000000000..51d8ac9a80 --- /dev/null +++ b/pkg/util/sysutils/hostname.go @@ -0,0 +1,30 @@ +package sysutils + +import ( + "fmt" + + "yunion.io/x/onecloud/pkg/util/fileutils2" + "yunion.io/x/onecloud/pkg/util/procutils" +) + +func setHostname7(name string) error { + _, err := procutils.NewCommand("hostnamectl", "set-hostname", name).Run() + return err +} + +func setHostname6(name string) error { + _, err := procutils.NewCommand("hostname", name).Run() + if err != nil { + return err + } + cont := fmt.Sprintf("NETWORKING=yes\nHOSTNAME=%s\n", name) + return fileutils2.FileSetContents("/etc/sysconfig/network", cont) +} + +func SetHostname(name string) error { + err := setHostname7(name) + if err != nil { + err = setHostname6(name) + } + return err +} diff --git a/pkg/util/sysutils/kvm.go b/pkg/util/sysutils/kvm.go new file mode 100644 index 0000000000..a37a72b485 --- /dev/null +++ b/pkg/util/sysutils/kvm.go @@ -0,0 +1,179 @@ +package sysutils + +import ( + "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_UNSUPPORT = "unsupport" + + 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 = detectiveKVMModuleSupport() + } + 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 detectiveKVMModuleSupport() 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 + } + 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.NewCommand(params[0], params[1:]...).Run(); err != nil { + 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) { + nestStatus = HOST_NEST_SUPPORT + } + + if nestStatus == HOST_NEST_SUPPORT && loadKvmModuleWithNest(moduleName) { + nestStatus = HOST_NEST_ENABLE + } + return nestStatus +} + +func isNestSupport(name string) bool { + output, err := procutils.NewCommand("modinfo", name).Run() + 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.NewCommand("lsmod").Run() + 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 +}