1
2
3 package hcs
4
5 import (
6 "context"
7 "strings"
8
9 "github.com/Microsoft/go-winio/pkg/guid"
10 "github.com/Microsoft/go-winio/pkg/process"
11 "github.com/Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1/stats"
12 hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2"
13 "github.com/Microsoft/hcsshim/internal/log"
14 "github.com/Microsoft/hcsshim/internal/vm"
15 "github.com/pkg/errors"
16 "github.com/sirupsen/logrus"
17 "golang.org/x/sys/windows"
18 )
19
20
21
22
23
24
25 func checkProcess(ctx context.Context, pid uint32, desiredProcessName string, desiredDomain string, desiredUser string) (p windows.Handle, err error) {
26 desiredProcessName = strings.ToUpper(desiredProcessName)
27 desiredDomain = strings.ToUpper(desiredDomain)
28 desiredUser = strings.ToUpper(desiredUser)
29
30 p, err = windows.OpenProcess(windows.PROCESS_QUERY_LIMITED_INFORMATION|windows.PROCESS_VM_READ, false, pid)
31 if err != nil {
32 return 0, err
33 }
34
35 defer func(openedProcess windows.Handle) {
36
37 if p == 0 {
38 windows.Close(openedProcess)
39 }
40 }(p)
41
42
43
44 name, err := process.QueryFullProcessImageName(p, process.ImageNameFormatNTPath)
45 if err != nil {
46 return 0, err
47 }
48 if strings.ToUpper(name) == desiredProcessName {
49 var t windows.Token
50 if err := windows.OpenProcessToken(p, windows.TOKEN_QUERY, &t); err != nil {
51 return 0, err
52 }
53 defer t.Close()
54 tUser, err := t.GetTokenUser()
55 if err != nil {
56 return 0, err
57 }
58 user, domain, _, err := tUser.User.Sid.LookupAccount("")
59 if err != nil {
60 return 0, err
61 }
62 log.G(ctx).WithFields(logrus.Fields{
63 "name": name,
64 "domain": domain,
65 "user": user,
66 }).Debug("checking vmmem process identity")
67 if strings.ToUpper(domain) == desiredDomain && strings.ToUpper(user) == desiredUser {
68 return p, nil
69 }
70 }
71 return 0, nil
72 }
73
74
75
76
77
78 func lookupVMMEM(ctx context.Context, vmID guid.GUID) (proc windows.Handle, err error) {
79 vmIDStr := strings.ToUpper(vmID.String())
80 log.G(ctx).WithField("vmID", vmIDStr).Debug("looking up vmmem")
81
82 pids, err := process.EnumProcesses()
83 if err != nil {
84 return 0, errors.Wrap(err, "failed to enumerate processes")
85 }
86 for _, pid := range pids {
87 p, err := checkProcess(ctx, pid, "vmmem", "NT VIRTUAL MACHINE", vmIDStr)
88 if err != nil {
89
90
91
92
93 log.G(ctx).WithField("pid", pid).Debug("failed to check process")
94 continue
95 }
96 if p != 0 {
97 log.G(ctx).WithField("pid", pid).Debug("found vmmem match")
98 return p, nil
99 }
100 }
101 return 0, errors.New("failed to find matching vmmem process")
102 }
103
104
105
106
107 func (uvm *utilityVM) getVMMEMProcess(ctx context.Context) (windows.Handle, error) {
108 uvm.vmmemOnce.Do(func() {
109 uvm.vmmemProcess, uvm.vmmemErr = lookupVMMEM(ctx, uvm.vmID)
110 })
111 return uvm.vmmemProcess, uvm.vmmemErr
112 }
113
114 func (uvm *utilityVM) Stats(ctx context.Context) (*stats.VirtualMachineStatistics, error) {
115 s := &stats.VirtualMachineStatistics{}
116 props, err := uvm.cs.PropertiesV2(ctx, hcsschema.PTStatistics, hcsschema.PTMemory)
117 if err != nil {
118 return nil, err
119 }
120
121 s.Processor = &stats.VirtualMachineProcessorStatistics{}
122 s.Processor.TotalRuntimeNS = uint64(props.Statistics.Processor.TotalRuntime100ns * 100)
123 s.Memory = &stats.VirtualMachineMemoryStatistics{}
124
125 if uvm.backingType == vm.MemoryBackingTypePhysical {
126
127
128
129 if props.Memory != nil {
130 s.Memory.WorkingSetBytes = props.Memory.VirtualMachineMemory.AssignedMemory * 4096
131 }
132 } else {
133
134
135
136
137 vmmemProc, err := uvm.getVMMEMProcess(ctx)
138 if err != nil {
139 return nil, err
140 }
141 memCounters, err := process.GetProcessMemoryInfo(vmmemProc)
142 if err != nil {
143 return nil, err
144 }
145 s.Memory.WorkingSetBytes = uint64(memCounters.WorkingSetSize)
146 }
147
148 if props.Memory != nil {
149 s.Memory.VirtualNodeCount = props.Memory.VirtualNodeCount
150 s.Memory.VmMemory = &stats.VirtualMachineMemory{}
151 s.Memory.VmMemory.AvailableMemory = props.Memory.VirtualMachineMemory.AvailableMemory
152 s.Memory.VmMemory.AvailableMemoryBuffer = props.Memory.VirtualMachineMemory.AvailableMemoryBuffer
153 s.Memory.VmMemory.ReservedMemory = props.Memory.VirtualMachineMemory.ReservedMemory
154 s.Memory.VmMemory.AssignedMemory = props.Memory.VirtualMachineMemory.AssignedMemory
155 s.Memory.VmMemory.SlpActive = props.Memory.VirtualMachineMemory.SlpActive
156 s.Memory.VmMemory.BalancingEnabled = props.Memory.VirtualMachineMemory.BalancingEnabled
157 s.Memory.VmMemory.DmOperationInProgress = props.Memory.VirtualMachineMemory.DmOperationInProgress
158 }
159
160 return s, nil
161 }
162
View as plain text