conversion.go 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. // Copyright 2015 Google Inc. All Rights Reserved.
  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. package v2
  15. import (
  16. "fmt"
  17. "time"
  18. "github.com/google/cadvisor/info/v1"
  19. "k8s.io/klog"
  20. )
  21. func machineFsStatsFromV1(fsStats []v1.FsStats) []MachineFsStats {
  22. var result []MachineFsStats
  23. for i := range fsStats {
  24. stat := fsStats[i]
  25. readDuration := time.Millisecond * time.Duration(stat.ReadTime)
  26. writeDuration := time.Millisecond * time.Duration(stat.WriteTime)
  27. ioDuration := time.Millisecond * time.Duration(stat.IoTime)
  28. weightedDuration := time.Millisecond * time.Duration(stat.WeightedIoTime)
  29. machineFsStat := MachineFsStats{
  30. Device: stat.Device,
  31. Type: stat.Type,
  32. Capacity: &stat.Limit,
  33. Usage: &stat.Usage,
  34. Available: &stat.Available,
  35. DiskStats: DiskStats{
  36. ReadsCompleted: &stat.ReadsCompleted,
  37. ReadsMerged: &stat.ReadsMerged,
  38. SectorsRead: &stat.SectorsRead,
  39. ReadDuration: &readDuration,
  40. WritesCompleted: &stat.WritesCompleted,
  41. WritesMerged: &stat.WritesMerged,
  42. SectorsWritten: &stat.SectorsWritten,
  43. WriteDuration: &writeDuration,
  44. IoInProgress: &stat.IoInProgress,
  45. IoDuration: &ioDuration,
  46. WeightedIoDuration: &weightedDuration,
  47. },
  48. }
  49. if stat.HasInodes {
  50. machineFsStat.InodesFree = &stat.InodesFree
  51. }
  52. result = append(result, machineFsStat)
  53. }
  54. return result
  55. }
  56. func MachineStatsFromV1(cont *v1.ContainerInfo) []MachineStats {
  57. var stats []MachineStats
  58. var last *v1.ContainerStats
  59. for i := range cont.Stats {
  60. val := cont.Stats[i]
  61. stat := MachineStats{
  62. Timestamp: val.Timestamp,
  63. }
  64. if cont.Spec.HasCpu {
  65. stat.Cpu = &val.Cpu
  66. cpuInst, err := InstCpuStats(last, val)
  67. if err != nil {
  68. klog.Warningf("Could not get instant cpu stats: %v", err)
  69. } else {
  70. stat.CpuInst = cpuInst
  71. }
  72. last = val
  73. }
  74. if cont.Spec.HasMemory {
  75. stat.Memory = &val.Memory
  76. }
  77. if cont.Spec.HasNetwork {
  78. stat.Network = &NetworkStats{
  79. // FIXME: Use reflection instead.
  80. Tcp: TcpStat(val.Network.Tcp),
  81. Tcp6: TcpStat(val.Network.Tcp6),
  82. Interfaces: val.Network.Interfaces,
  83. }
  84. }
  85. if cont.Spec.HasFilesystem {
  86. stat.Filesystem = machineFsStatsFromV1(val.Filesystem)
  87. }
  88. // TODO(rjnagal): Handle load stats.
  89. stats = append(stats, stat)
  90. }
  91. return stats
  92. }
  93. func ContainerStatsFromV1(containerName string, spec *v1.ContainerSpec, stats []*v1.ContainerStats) []*ContainerStats {
  94. newStats := make([]*ContainerStats, 0, len(stats))
  95. var last *v1.ContainerStats
  96. for _, val := range stats {
  97. stat := &ContainerStats{
  98. Timestamp: val.Timestamp,
  99. }
  100. if spec.HasCpu {
  101. stat.Cpu = &val.Cpu
  102. cpuInst, err := InstCpuStats(last, val)
  103. if err != nil {
  104. klog.Warningf("Could not get instant cpu stats: %v", err)
  105. } else {
  106. stat.CpuInst = cpuInst
  107. }
  108. last = val
  109. }
  110. if spec.HasMemory {
  111. stat.Memory = &val.Memory
  112. }
  113. if spec.HasNetwork {
  114. // TODO: Handle TcpStats
  115. stat.Network = &NetworkStats{
  116. Tcp: TcpStat(val.Network.Tcp),
  117. Tcp6: TcpStat(val.Network.Tcp6),
  118. Interfaces: val.Network.Interfaces,
  119. }
  120. }
  121. if spec.HasProcesses {
  122. stat.Processes = &val.Processes
  123. }
  124. if spec.HasFilesystem {
  125. if len(val.Filesystem) == 1 {
  126. stat.Filesystem = &FilesystemStats{
  127. TotalUsageBytes: &val.Filesystem[0].Usage,
  128. BaseUsageBytes: &val.Filesystem[0].BaseUsage,
  129. InodeUsage: &val.Filesystem[0].Inodes,
  130. }
  131. } else if len(val.Filesystem) > 1 && containerName != "/" {
  132. // Cannot handle multiple devices per container.
  133. klog.V(4).Infof("failed to handle multiple devices for container %s. Skipping Filesystem stats", containerName)
  134. }
  135. }
  136. if spec.HasDiskIo {
  137. stat.DiskIo = &val.DiskIo
  138. }
  139. if spec.HasCustomMetrics {
  140. stat.CustomMetrics = val.CustomMetrics
  141. }
  142. if len(val.Accelerators) > 0 {
  143. stat.Accelerators = val.Accelerators
  144. }
  145. // TODO(rjnagal): Handle load stats.
  146. newStats = append(newStats, stat)
  147. }
  148. return newStats
  149. }
  150. func DeprecatedStatsFromV1(cont *v1.ContainerInfo) []DeprecatedContainerStats {
  151. stats := make([]DeprecatedContainerStats, 0, len(cont.Stats))
  152. var last *v1.ContainerStats
  153. for _, val := range cont.Stats {
  154. stat := DeprecatedContainerStats{
  155. Timestamp: val.Timestamp,
  156. HasCpu: cont.Spec.HasCpu,
  157. HasMemory: cont.Spec.HasMemory,
  158. HasNetwork: cont.Spec.HasNetwork,
  159. HasFilesystem: cont.Spec.HasFilesystem,
  160. HasDiskIo: cont.Spec.HasDiskIo,
  161. HasCustomMetrics: cont.Spec.HasCustomMetrics,
  162. }
  163. if stat.HasCpu {
  164. stat.Cpu = val.Cpu
  165. cpuInst, err := InstCpuStats(last, val)
  166. if err != nil {
  167. klog.Warningf("Could not get instant cpu stats: %v", err)
  168. } else {
  169. stat.CpuInst = cpuInst
  170. }
  171. last = val
  172. }
  173. if stat.HasMemory {
  174. stat.Memory = val.Memory
  175. }
  176. if stat.HasNetwork {
  177. stat.Network.Interfaces = val.Network.Interfaces
  178. }
  179. if stat.HasProcesses {
  180. stat.Processes = val.Processes
  181. }
  182. if stat.HasFilesystem {
  183. stat.Filesystem = val.Filesystem
  184. }
  185. if stat.HasDiskIo {
  186. stat.DiskIo = val.DiskIo
  187. }
  188. if stat.HasCustomMetrics {
  189. stat.CustomMetrics = val.CustomMetrics
  190. }
  191. // TODO(rjnagal): Handle load stats.
  192. stats = append(stats, stat)
  193. }
  194. return stats
  195. }
  196. func InstCpuStats(last, cur *v1.ContainerStats) (*CpuInstStats, error) {
  197. if last == nil {
  198. return nil, nil
  199. }
  200. if !cur.Timestamp.After(last.Timestamp) {
  201. return nil, fmt.Errorf("container stats move backwards in time")
  202. }
  203. if len(last.Cpu.Usage.PerCpu) != len(cur.Cpu.Usage.PerCpu) {
  204. return nil, fmt.Errorf("different number of cpus")
  205. }
  206. timeDelta := cur.Timestamp.Sub(last.Timestamp)
  207. // Nanoseconds to gain precision and avoid having zero seconds if the
  208. // difference between the timestamps is just under a second
  209. timeDeltaNs := uint64(timeDelta.Nanoseconds())
  210. convertToRate := func(lastValue, curValue uint64) (uint64, error) {
  211. if curValue < lastValue {
  212. return 0, fmt.Errorf("cumulative stats decrease")
  213. }
  214. valueDelta := curValue - lastValue
  215. // Use float64 to keep precision
  216. return uint64(float64(valueDelta) / float64(timeDeltaNs) * 1e9), nil
  217. }
  218. total, err := convertToRate(last.Cpu.Usage.Total, cur.Cpu.Usage.Total)
  219. if err != nil {
  220. return nil, err
  221. }
  222. percpu := make([]uint64, len(last.Cpu.Usage.PerCpu))
  223. for i := range percpu {
  224. var err error
  225. percpu[i], err = convertToRate(last.Cpu.Usage.PerCpu[i], cur.Cpu.Usage.PerCpu[i])
  226. if err != nil {
  227. return nil, err
  228. }
  229. }
  230. user, err := convertToRate(last.Cpu.Usage.User, cur.Cpu.Usage.User)
  231. if err != nil {
  232. return nil, err
  233. }
  234. system, err := convertToRate(last.Cpu.Usage.System, cur.Cpu.Usage.System)
  235. if err != nil {
  236. return nil, err
  237. }
  238. return &CpuInstStats{
  239. Usage: CpuInstUsage{
  240. Total: total,
  241. PerCpu: percpu,
  242. User: user,
  243. System: system,
  244. },
  245. }, nil
  246. }
  247. // Get V2 container spec from v1 container info.
  248. func ContainerSpecFromV1(specV1 *v1.ContainerSpec, aliases []string, namespace string) ContainerSpec {
  249. specV2 := ContainerSpec{
  250. CreationTime: specV1.CreationTime,
  251. HasCpu: specV1.HasCpu,
  252. HasMemory: specV1.HasMemory,
  253. HasFilesystem: specV1.HasFilesystem,
  254. HasNetwork: specV1.HasNetwork,
  255. HasProcesses: specV1.HasProcesses,
  256. HasDiskIo: specV1.HasDiskIo,
  257. HasCustomMetrics: specV1.HasCustomMetrics,
  258. Image: specV1.Image,
  259. Labels: specV1.Labels,
  260. Envs: specV1.Envs,
  261. }
  262. if specV1.HasCpu {
  263. specV2.Cpu.Limit = specV1.Cpu.Limit
  264. specV2.Cpu.MaxLimit = specV1.Cpu.MaxLimit
  265. specV2.Cpu.Mask = specV1.Cpu.Mask
  266. }
  267. if specV1.HasMemory {
  268. specV2.Memory.Limit = specV1.Memory.Limit
  269. specV2.Memory.Reservation = specV1.Memory.Reservation
  270. specV2.Memory.SwapLimit = specV1.Memory.SwapLimit
  271. }
  272. if specV1.HasCustomMetrics {
  273. specV2.CustomMetrics = specV1.CustomMetrics
  274. }
  275. specV2.Aliases = aliases
  276. specV2.Namespace = namespace
  277. return specV2
  278. }