Skip to content

Commit 820f97f

Browse files
authored
Merge pull request #831 from Mirantis/jell/ucr
Set cpuset for emulator during UpdateContainerResources
2 parents 36bc8d1 + e1e1c94 commit 820f97f

11 files changed

+164
-44
lines changed

deploy/data/virtlet-ds.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,8 @@ spec:
213213
- name: netns-dir
214214
mountPath: /var/run/netns
215215
mountPropagation: Bidirectional
216+
- name: cgroup
217+
mountPath: /sys/fs/cgroup
216218
securityContext:
217219
privileged: true
218220
readinessProbe:

pkg/libvirttools/cpusets.go

+138
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
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+
"bytes"
21+
"io/ioutil"
22+
"os"
23+
"path/filepath"
24+
"strconv"
25+
"strings"
26+
27+
libvirtxml "github.com/libvirt/libvirt-go-xml"
28+
29+
vconfig "github.com/Mirantis/virtlet/pkg/config"
30+
"github.com/Mirantis/virtlet/pkg/utils/cgroups"
31+
)
32+
33+
const (
34+
procfsLocation = "/proc"
35+
emulatorProcessName = "qemu-system-x86_64"
36+
)
37+
38+
// UpdateCpusetsInContainerDefinition updates libvirt domain definition for the VM
39+
// setting the environment variable which is used by vmwrapper to pin to the specified cpuset
40+
func (v *VirtualizationTool) UpdateCpusetsInContainerDefinition(containerID, cpusets string) error {
41+
domain, err := v.domainConn.LookupDomainByUUIDString(containerID)
42+
if err != nil {
43+
return err
44+
}
45+
46+
domainxml, err := domain.XML()
47+
if err != nil {
48+
return err
49+
}
50+
51+
found := false
52+
envvars := domainxml.QEMUCommandline.Envs
53+
for _, envvar := range envvars {
54+
if envvar.Name == vconfig.CpusetsEnvVarName {
55+
envvar.Value = cpusets
56+
found = true
57+
}
58+
}
59+
if !found && cpusets != "" {
60+
domainxml.QEMUCommandline.Envs = append(envvars, libvirtxml.DomainQEMUCommandlineEnv{
61+
Name: vconfig.CpusetsEnvVarName,
62+
Value: cpusets,
63+
})
64+
}
65+
66+
if err := domain.Undefine(); err != nil {
67+
return err
68+
}
69+
70+
_, err = v.domainConn.DefineDomain(domainxml)
71+
return err
72+
}
73+
74+
// UpdateCpusetsForEmulatorProcess looks through /proc for emulator process
75+
// to find its cgroup manager for cpusets then uses it to adjust the setting
76+
func (v *VirtualizationTool) UpdateCpusetsForEmulatorProcess(containerID, cpusets string) (bool, error) {
77+
// TODO: replace iterating over the procfs with reading pid from
78+
// /run/libvirt/qemu/virtlet-CONTAINER_ID[:12]-DOMAIN_NAME.pid
79+
d, err := os.Open(procfsLocation)
80+
if err != nil {
81+
return false, err
82+
}
83+
defer d.Close()
84+
85+
entries, err := d.Readdirnames(-1)
86+
if err != nil {
87+
return false, err
88+
}
89+
90+
for _, name := range entries {
91+
_, err := strconv.ParseInt(name, 10, 32)
92+
if err != nil {
93+
// skip non numeric names
94+
continue
95+
}
96+
97+
isContainerPid, err := isEmulatorPid(name, containerID)
98+
if err != nil {
99+
return false, err
100+
}
101+
102+
if isContainerPid {
103+
controller, err := cgroups.GetProcessController(name, "cpuset")
104+
if err != nil {
105+
return false, err
106+
}
107+
108+
if err := controller.Set("cpus", cpusets); err != nil {
109+
return false, err
110+
}
111+
return true, nil
112+
}
113+
}
114+
115+
return false, nil
116+
}
117+
118+
func isEmulatorPid(pid, containerID string) (bool, error) {
119+
data, err := ioutil.ReadFile(filepath.Join(procfsLocation, pid, "cmdline"))
120+
if err != nil {
121+
return false, err
122+
}
123+
124+
cmdline := bytes.Split(data, []byte{0})
125+
126+
if string(cmdline[0]) != emulatorProcessName {
127+
return false, nil
128+
}
129+
130+
searchTerm := "virtlet-" + containerID[:12]
131+
for _, param := range cmdline {
132+
if strings.Contains(string(param), searchTerm) {
133+
return true, nil
134+
}
135+
}
136+
137+
return false, nil
138+
}

pkg/libvirttools/virtualization.go

-37
Original file line numberDiff line numberDiff line change
@@ -818,43 +818,6 @@ func (v *VirtualizationTool) ContainerInfo(containerID string) (*types.Container
818818
return containerInfo, nil
819819
}
820820

821-
// UpdateCpusetsInContainerDefinition updates domain definition in libvirt for the VM
822-
// setting environment variable for vmwrapper with info about to which cpuset it should
823-
// pin itself
824-
func (v *VirtualizationTool) UpdateCpusetsInContainerDefinition(containerID, cpusets string) error {
825-
domain, err := v.domainConn.LookupDomainByUUIDString(containerID)
826-
if err != nil {
827-
return err
828-
}
829-
830-
domainxml, err := domain.XML()
831-
if err != nil {
832-
return err
833-
}
834-
835-
found := false
836-
envvars := domainxml.QEMUCommandline.Envs
837-
for _, envvar := range envvars {
838-
if envvar.Name == vconfig.CpusetsEnvVarName {
839-
envvar.Value = cpusets
840-
found = true
841-
}
842-
}
843-
if !found && cpusets != "" {
844-
domainxml.QEMUCommandline.Envs = append(envvars, libvirtxml.DomainQEMUCommandlineEnv{
845-
Name: vconfig.CpusetsEnvVarName,
846-
Value: cpusets,
847-
})
848-
}
849-
850-
if err := domain.Undefine(); err != nil {
851-
return err
852-
}
853-
854-
_, err = v.domainConn.DefineDomain(domainxml)
855-
return err
856-
}
857-
858821
// VMStats returns current cpu/memory/disk usage for VM
859822
func (v *VirtualizationTool) VMStats(containerID string, name string) (*types.VMStats, error) {
860823
domain, err := v.domainConn.LookupDomainByUUIDString(containerID)

pkg/manager/runtime.go

+10-3
Original file line numberDiff line numberDiff line change
@@ -430,12 +430,19 @@ func (v *VirtletRuntimeService) UpdateRuntimeConfig(context.Context, *kubeapi.Up
430430
return &kubeapi.UpdateRuntimeConfigResponse{}, nil
431431
}
432432

433-
// UpdateContainerResources passes info about Cpusets for particular container
434-
// to virttool
433+
// UpdateContainerResources stores in domain on libvirt info about Cpuset
434+
// for container then looks for running emulator and tries to adjust its
435+
// current settings through cgroups
435436
func (v *VirtletRuntimeService) UpdateContainerResources(ctx context.Context, req *kubeapi.UpdateContainerResourcesRequest) (*kubeapi.UpdateContainerResourcesResponse, error) {
436-
if err := v.virtTool.UpdateCpusetsInContainerDefinition(req.GetContainerId(), req.GetLinux().CpusetCpus); err != nil {
437+
setByCgroup, err := v.virtTool.UpdateCpusetsForEmulatorProcess(req.GetContainerId(), req.GetLinux().CpusetCpus)
438+
if err != nil {
437439
return nil, err
438440
}
441+
if !setByCgroup {
442+
if err = v.virtTool.UpdateCpusetsInContainerDefinition(req.GetContainerId(), req.GetLinux().CpusetCpus); err != nil {
443+
return nil, err
444+
}
445+
}
439446
return &kubeapi.UpdateContainerResourcesResponse{}, nil
440447
}
441448

pkg/tools/TestGenCommand__compat.out.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,8 @@ spec:
108108
- mountPath: /var/run/netns
109109
mountPropagation: Bidirectional
110110
name: netns-dir
111+
- mountPath: /sys/fs/cgroup
112+
name: cgroup
111113
- command:
112114
- /vms.sh
113115
image: mirantis/virtlet

pkg/tools/TestGenCommand__compat_dev.out.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,8 @@ spec:
110110
- mountPath: /var/run/netns
111111
mountPropagation: Bidirectional
112112
name: netns-dir
113+
- mountPath: /sys/fs/cgroup
114+
name: cgroup
113115
- mountPath: /dind
114116
name: dind
115117
- command:

pkg/tools/TestGenCommand__dev.out.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@ spec:
111111
- mountPath: /var/run/netns
112112
mountPropagation: Bidirectional
113113
name: netns-dir
114+
- mountPath: /sys/fs/cgroup
115+
name: cgroup
114116
- mountPath: /dind
115117
name: dind
116118
- command:

pkg/tools/TestGenCommand__plain.out.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@ spec:
109109
- mountPath: /var/run/netns
110110
mountPropagation: Bidirectional
111111
name: netns-dir
112+
- mountPath: /sys/fs/cgroup
113+
name: cgroup
112114
- command:
113115
- /vms.sh
114116
image: mirantis/virtlet

pkg/tools/TestGenCommand__tag.out.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@ spec:
109109
- mountPath: /var/run/netns
110110
mountPropagation: Bidirectional
111111
name: netns-dir
112+
- mountPath: /sys/fs/cgroup
113+
name: cgroup
112114
- command:
113115
- /vms.sh
114116
image: mirantis/virtlet:0.9.42

pkg/tools/bindata.go

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/utils/cgroups/controllers.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,15 @@ const (
3737
func GetProcessControllers(pid interface{}) (map[string]string, error) {
3838
sPid := utils.Stringify(pid)
3939

40-
file, err := os.Open(filepath.Join("/proc", sPid, "cgroups"))
40+
file, err := os.Open(filepath.Join("/proc", sPid, "cgroup"))
4141
if err != nil {
4242
return nil, err
4343
}
4444
defer file.Close()
4545

4646
reader := bufio.NewReader(file)
4747

48-
var ctrls map[string]string
48+
ctrls := make(map[string]string)
4949

5050
for {
5151
line, err := reader.ReadString('\n')

0 commit comments

Comments
 (0)