|
|
@@ -11,8 +11,17 @@ import ( |
|
|
"github.com/libvirt/libvirt-go"
|
|
|
k8sv1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
|
|
|
|
"os"
|
|
|
|
|
|
"syscall"
|
|
|
|
|
|
"os/signal"
|
|
|
|
|
|
"k8s.io/apimachinery/pkg/util/wait"
|
|
|
|
|
|
"kubevirt.io/kubevirt/pkg/api/v1"
|
|
|
"kubevirt.io/kubevirt/pkg/log"
|
|
|
"kubevirt.io/kubevirt/pkg/virt-launcher"
|
|
|
"kubevirt.io/kubevirt/pkg/virt-launcher/virtwrap/api"
|
|
|
"kubevirt.io/kubevirt/pkg/virt-launcher/virtwrap/cli"
|
|
|
)
|
|
|
@@ -140,11 +149,10 @@ func StartLibvirt(stopChan chan struct{}) { |
|
|
// doesn't exit until virt-launcher is ready for it to. Virt-launcher traps signals
|
|
|
// to perform special shutdown logic. These processes need to live in the same
|
|
|
// container.
|
|
|
|
|
|
go func() {
|
|
|
for {
|
|
|
exitChan := make(chan struct{})
|
|
|
cmd := exec.Command("/usr/share/kubevirt/virt-launcher/libvirtd.sh")
|
|
|
cmd := exec.Command("/usr/sbin/libvirtd")
|
|
|
|
|
|
err := cmd.Start()
|
|
|
if err != nil {
|
|
|
@@ -162,7 +170,11 @@ func StartLibvirt(stopChan chan struct{}) { |
|
|
cmd.Process.Kill()
|
|
|
return
|
|
|
case <-exitChan:
|
|
|
log.Log.Errorf("libvirtd exited, restarting")
|
|
|
output, e := cmd.CombinedOutput()
|
|
|
if e == nil {
|
|
|
e = fmt.Errorf(string(output))
|
|
|
}
|
|
|
log.Log.Reason(e).Errorf("libvirtd exited, restarting")
|
|
|
}
|
|
|
|
|
|
// this sleep is to avoid consumming all resources in the
|
|
|
@@ -237,3 +249,102 @@ func NewDomain(dom cli.VirDomain) (*api.Domain, error) { |
|
|
domain.GetObjectMeta().SetUID(domain.Spec.Metadata.KubeVirt.UID)
|
|
|
return domain, nil
|
|
|
}
|
|
|
|
|
|
// ForkAndMonitor itself to give qemu an extra grace period to properly terminate
|
|
|
// in case of virt-launcher crashes
|
|
|
func ForkAndMonitor(commandNamePrefix string) error {
|
|
|
cmd := exec.Command(os.Args[0], append(os.Args[1:], "--no-fork", "true")...)
|
|
|
err := cmd.Start()
|
|
|
if err != nil {
|
|
|
log.Log.Reason(err).Error("failed to fork virt-launcher")
|
|
|
return err
|
|
|
}
|
|
|
|
|
|
sigs := make(chan os.Signal, 1)
|
|
|
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
|
|
|
go func() {
|
|
|
for sig := range sigs {
|
|
|
log.Log.V(3).Log("signalling virt-launcher to shut down")
|
|
|
err := cmd.Process.Kill()
|
|
|
if err != nil {
|
|
|
log.Log.Reason(err).Errorf("received signal %s but can't signal virt-launcher to shut down", sig.String())
|
|
|
}
|
|
|
}
|
|
|
}()
|
|
|
|
|
|
if err := cmd.Wait(); err != nil {
|
|
|
exitCode := 1
|
|
|
if exiterr, ok := err.(*exec.ExitError); ok {
|
|
|
if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
|
|
|
exitCode = status.ExitStatus()
|
|
|
}
|
|
|
}
|
|
|
log.Log.Reason(err).Error("dirty virt-launcher shutdown")
|
|
|
pid, _ := virtlauncher.FindPid(commandNamePrefix)
|
|
|
if pid > 0 {
|
|
|
p, err := os.FindProcess(pid)
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
// Signal qemu to shutdown
|
|
|
err = p.Signal(syscall.SIGTERM)
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
// Wait for 10 seconds for the qemu process to disappear
|
|
|
err = wait.PollImmediate(1*time.Second, 10*time.Second, func() (bool, error) {
|
|
|
pid, _ := virtlauncher.FindPid(commandNamePrefix)
|
|
|
if pid == 0 {
|
|
|
return true, nil
|
|
|
}
|
|
|
return false, nil
|
|
|
})
|
|
|
}
|
|
|
os.Exit(exitCode)
|
|
|
}
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
func SetupLibvirt() error {
|
|
|
|
|
|
// TODO: setting permissions and owners is not part of device plugins.
|
|
|
// Configure these manually right now on "/dev/kvm"
|
|
|
stats, err := os.Stat("/dev/kvm")
|
|
|
if err == nil {
|
|
|
s, ok := stats.Sys().(*syscall.Stat_t)
|
|
|
if !ok {
|
|
|
return fmt.Errorf("can't convert file stats to unix/linux stats")
|
|
|
}
|
|
|
err := os.Chown("/dev/kvm", int(s.Uid), 107)
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
err = os.Chmod("/dev/kvm", 0660)
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
} else if !os.IsNotExist(err) {
|
|
|
return err
|
|
|
}
|
|
|
|
|
|
qemuConf, err := os.OpenFile("/etc/libvirt/qemu.conf", os.O_APPEND|os.O_WRONLY, 0644)
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
defer qemuConf.Close()
|
|
|
// We are in a container, don't try to stuff qemu inside special cgroups
|
|
|
_, err = qemuConf.WriteString("cgroup_controllers = [ ]\n")
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
|
|
|
// If hugepages exist, tell libvirt about them
|
|
|
_, err = os.Stat("/dev/hugepages")
|
|
|
if err == nil {
|
|
|
_, err = qemuConf.WriteString("hugetlbfs_mount = \"/dev/hugepages\"\n")
|
|
|
} else if !os.IsNotExist(err) {
|
|
|
return err
|
|
|
}
|
|
|
|
|
|
return nil
|
|
|
}
|