github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/runsc/boot/events.go (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package boot 16 17 import ( 18 "errors" 19 20 "github.com/nicocha30/gvisor-ligolo/pkg/sentry/control" 21 "github.com/nicocha30/gvisor-ligolo/pkg/sentry/usage" 22 ) 23 24 // EventOut is the return type of the Event command. 25 type EventOut struct { 26 Event Event `json:"event"` 27 28 // ContainerUsage maps each container ID to its total CPU usage. 29 ContainerUsage map[string]uint64 `json:"containerUsage"` 30 } 31 32 // Event struct for encoding the event data to JSON. Corresponds to runc's 33 // main.event struct. 34 type Event struct { 35 Type string `json:"type"` 36 ID string `json:"id"` 37 Data Stats `json:"data"` 38 } 39 40 // Stats is the runc specific stats structure for stability when encoding and 41 // decoding stats. 42 type Stats struct { 43 CPU CPU `json:"cpu"` 44 Memory Memory `json:"memory"` 45 Pids Pids `json:"pids"` 46 } 47 48 // Pids contains stats on processes. 49 type Pids struct { 50 Current uint64 `json:"current,omitempty"` 51 Limit uint64 `json:"limit,omitempty"` 52 } 53 54 // MemoryEntry contains stats on a kind of memory. 55 type MemoryEntry struct { 56 Limit uint64 `json:"limit"` 57 Usage uint64 `json:"usage,omitempty"` 58 Max uint64 `json:"max,omitempty"` 59 Failcnt uint64 `json:"failcnt"` 60 } 61 62 // Memory contains stats on memory. 63 type Memory struct { 64 Cache uint64 `json:"cache,omitempty"` 65 Usage MemoryEntry `json:"usage,omitempty"` 66 Swap MemoryEntry `json:"swap,omitempty"` 67 Kernel MemoryEntry `json:"kernel,omitempty"` 68 KernelTCP MemoryEntry `json:"kernelTCP,omitempty"` 69 Raw map[string]uint64 `json:"raw,omitempty"` 70 } 71 72 // CPU contains stats on the CPU. 73 type CPU struct { 74 Usage CPUUsage `json:"usage"` 75 } 76 77 // CPUUsage contains stats on CPU usage. 78 type CPUUsage struct { 79 Kernel uint64 `json:"kernel,omitempty"` 80 User uint64 `json:"user,omitempty"` 81 Total uint64 `json:"total,omitempty"` 82 PerCPU []uint64 `json:"percpu,omitempty"` 83 } 84 85 // Event gets the events from the container. 86 func (cm *containerManager) Event(cid *string, out *EventOut) error { 87 *out = EventOut{ 88 Event: Event{ 89 ID: *cid, 90 Type: "stats", 91 }, 92 } 93 94 // Memory usage. 95 mem := cm.l.k.MemoryFile() 96 _ = mem.UpdateUsage() // best effort to update. 97 _, totalUsage := usage.MemoryAccounting.Copy() 98 switch containers := cm.l.containerCount(); containers { 99 case 0: 100 return errors.New("no container was found") 101 102 case 1: 103 // There is a single container, so total usage can only come from it. 104 105 default: 106 // In the multi-container case, reports 0 for the root (pause) container, 107 // since it's small and idle. Then equally split the usage to the other 108 // containers. At least the sum of all containers will correctly account 109 // for the memory used by the sandbox. 110 // 111 // TODO(gvisor.dev/issue/172): Proper per-container accounting. 112 if *cid == cm.l.sandboxID { 113 totalUsage = 0 114 } else { 115 totalUsage /= uint64(containers - 1) 116 } 117 } 118 119 out.Event.Data.Memory.Usage.Usage = totalUsage 120 121 // PIDs. 122 // TODO(gvisor.dev/issue/172): Per-container accounting. 123 out.Event.Data.Pids.Current = uint64(len(cm.l.k.TaskSet().Root.ThreadGroups())) 124 125 // CPU usage by container. 126 out.ContainerUsage = control.ContainerUsage(cm.l.k) 127 128 return nil 129 }