github.com/mirantis/virtlet@v1.5.2-0.20191204181327-1659b8a48e9b/pkg/libvirttools/cpusets.go (about) 1 /* 2 Copyright 2018 Mirantis 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package libvirttools 18 19 import ( 20 "fmt" 21 "io" 22 "os" 23 24 libvirtxml "github.com/libvirt/libvirt-go-xml" 25 26 vconfig "github.com/Mirantis/virtlet/pkg/config" 27 "github.com/Mirantis/virtlet/pkg/utils/cgroups" 28 ) 29 30 const ( 31 procfsLocation = "/proc" 32 emulatorProcessName = "qemu-system-x86_64" 33 ) 34 35 // UpdateCpusetsInContainerDefinition updates libvirt domain definition for the VM 36 // setting the environment variable which is used by vmwrapper to pin to the specified cpuset 37 func (v *VirtualizationTool) UpdateCpusetsInContainerDefinition(containerID, cpusets string) error { 38 domain, err := v.domainConn.LookupDomainByUUIDString(containerID) 39 if err != nil { 40 return err 41 } 42 43 domainxml, err := domain.XML() 44 if err != nil { 45 return err 46 } 47 48 found := false 49 envvars := domainxml.QEMUCommandline.Envs 50 for _, envvar := range envvars { 51 if envvar.Name == vconfig.CpusetsEnvVarName { 52 envvar.Value = cpusets 53 found = true 54 } 55 } 56 if !found && cpusets != "" { 57 domainxml.QEMUCommandline.Envs = append(envvars, libvirtxml.DomainQEMUCommandlineEnv{ 58 Name: vconfig.CpusetsEnvVarName, 59 Value: cpusets, 60 }) 61 } 62 63 if err := domain.Undefine(); err != nil { 64 return err 65 } 66 67 _, err = v.domainConn.DefineDomain(domainxml) 68 return err 69 } 70 71 // UpdateCpusetsForEmulatorProcess looks through /proc for emulator process 72 // to find its cgroup manager for cpusets then uses it to adjust the setting 73 func (v *VirtualizationTool) UpdateCpusetsForEmulatorProcess(containerID, cpusets string) (bool, error) { 74 pidFilePath, err := v.getEmulatorPidFileLocation(containerID) 75 if err != nil { 76 return false, err 77 } 78 79 f, err := v.fsys.GetDelimitedReader(pidFilePath) 80 if err != nil { 81 // File not found - so there is no emulator yet 82 if _, ok := err.(*os.PathError); ok { 83 return false, nil 84 } 85 return false, err 86 } 87 defer f.Close() 88 89 // there should be only a single line without eol, but use eol as 90 // a marker to read data to EOF. 91 pid, err := f.ReadString('\n') 92 if err != nil { 93 if err != io.EOF { 94 return false, err 95 } 96 } 97 98 cm := cgroups.NewManager(pid, v.fsys) 99 controller, err := cm.GetProcessController("cpuset") 100 if err != nil { 101 return false, err 102 } 103 104 if err := controller.Set("cpus", cpusets); err != nil { 105 return false, err 106 } 107 return true, nil 108 } 109 110 func (v *VirtualizationTool) getEmulatorPidFileLocation(containerID string) (string, error) { 111 container, err := v.metadataStore.Container(containerID).Retrieve() 112 if err != nil { 113 return "", err 114 } 115 return fmt.Sprintf( 116 "/run/libvirt/qemu/virtlet-%s-%s.pid", 117 containerID[:13], container.Config.PodName, 118 ), nil 119 }