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  }