conversion.go 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  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.HasFilesystem {
  122. if len(val.Filesystem) == 1 {
  123. stat.Filesystem = &FilesystemStats{
  124. TotalUsageBytes: &val.Filesystem[0].Usage,
  125. BaseUsageBytes: &val.Filesystem[0].BaseUsage,
  126. InodeUsage: &val.Filesystem[0].Inodes,
  127. }
  128. } else if len(val.Filesystem) > 1 && containerName != "/" {
  129. // Cannot handle multiple devices per container.
  130. klog.V(4).Infof("failed to handle multiple devices for container %s. Skipping Filesystem stats", containerName)
  131. }
  132. }
  133. if spec.HasDiskIo {
  134. stat.DiskIo = &val.DiskIo
  135. }
  136. if spec.HasCustomMetrics {
  137. stat.CustomMetrics = val.CustomMetrics
  138. }
  139. if len(val.Accelerators) > 0 {
  140. stat.Accelerators = val.Accelerators
  141. }
  142. // TODO(rjnagal): Handle load stats.
  143. newStats = append(newStats, stat)
  144. }
  145. return newStats
  146. }
  147. func DeprecatedStatsFromV1(cont *v1.ContainerInfo) []DeprecatedContainerStats {
  148. stats := make([]DeprecatedContainerStats, 0, len(cont.Stats))
  149. var last *v1.ContainerStats
  150. for _, val := range cont.Stats {
  151. stat := DeprecatedContainerStats{
  152. Timestamp: val.Timestamp,
  153. HasCpu: cont.Spec.HasCpu,
  154. HasMemory: cont.Spec.HasMemory,
  155. HasNetwork: cont.Spec.HasNetwork,
  156. HasFilesystem: cont.Spec.HasFilesystem,
  157. HasDiskIo: cont.Spec.HasDiskIo,
  158. HasCustomMetrics: cont.Spec.HasCustomMetrics,
  159. }
  160. if stat.HasCpu {
  161. stat.Cpu = val.Cpu
  162. cpuInst, err := InstCpuStats(last, val)
  163. if err != nil {
  164. klog.Warningf("Could not get instant cpu stats: %v", err)
  165. } else {
  166. stat.CpuInst = cpuInst
  167. }
  168. last = val
  169. }
  170. if stat.HasMemory {
  171. stat.Memory = val.Memory
  172. }
  173. if stat.HasNetwork {
  174. stat.Network.Interfaces = val.Network.Interfaces
  175. }
  176. if stat.HasFilesystem {
  177. stat.Filesystem = val.Filesystem
  178. }
  179. if stat.HasDiskIo {
  180. stat.DiskIo = val.DiskIo
  181. }
  182. if stat.HasCustomMetrics {
  183. stat.CustomMetrics = val.CustomMetrics
  184. }
  185. // TODO(rjnagal): Handle load stats.
  186. stats = append(stats, stat)
  187. }
  188. return stats
  189. }
  190. func InstCpuStats(last, cur *v1.ContainerStats) (*CpuInstStats, error) {
  191. if last == nil {
  192. return nil, nil
  193. }
  194. if !cur.Timestamp.After(last.Timestamp) {
  195. return nil, fmt.Errorf("container stats move backwards in time")
  196. }
  197. if len(last.Cpu.Usage.PerCpu) != len(cur.Cpu.Usage.PerCpu) {
  198. return nil, fmt.Errorf("different number of cpus")
  199. }
  200. timeDelta := cur.Timestamp.Sub(last.Timestamp)
  201. // Nanoseconds to gain precision and avoid having zero seconds if the
  202. // difference between the timestamps is just under a second
  203. timeDeltaNs := uint64(timeDelta.Nanoseconds())
  204. convertToRate := func(lastValue, curValue uint64) (uint64, error) {
  205. if curValue < lastValue {
  206. return 0, fmt.Errorf("cumulative stats decrease")
  207. }
  208. valueDelta := curValue - lastValue
  209. // Use float64 to keep precision
  210. return uint64(float64(valueDelta) / float64(timeDeltaNs) * 1e9), nil
  211. }
  212. total, err := convertToRate(last.Cpu.Usage.Total, cur.Cpu.Usage.Total)
  213. if err != nil {
  214. return nil, err
  215. }
  216. percpu := make([]uint64, len(last.Cpu.Usage.PerCpu))
  217. for i := range percpu {
  218. var err error
  219. percpu[i], err = convertToRate(last.Cpu.Usage.PerCpu[i], cur.Cpu.Usage.PerCpu[i])
  220. if err != nil {
  221. return nil, err
  222. }
  223. }
  224. user, err := convertToRate(last.Cpu.Usage.User, cur.Cpu.Usage.User)
  225. if err != nil {
  226. return nil, err
  227. }
  228. system, err := convertToRate(last.Cpu.Usage.System, cur.Cpu.Usage.System)
  229. if err != nil {
  230. return nil, err
  231. }
  232. return &CpuInstStats{
  233. Usage: CpuInstUsage{
  234. Total: total,
  235. PerCpu: percpu,
  236. User: user,
  237. System: system,
  238. },
  239. }, nil
  240. }
  241. // Get V2 container spec from v1 container info.
  242. func ContainerSpecFromV1(specV1 *v1.ContainerSpec, aliases []string, namespace string) ContainerSpec {
  243. specV2 := ContainerSpec{
  244. CreationTime: specV1.CreationTime,
  245. HasCpu: specV1.HasCpu,
  246. HasMemory: specV1.HasMemory,
  247. HasFilesystem: specV1.HasFilesystem,
  248. HasNetwork: specV1.HasNetwork,
  249. HasDiskIo: specV1.HasDiskIo,
  250. HasCustomMetrics: specV1.HasCustomMetrics,
  251. Image: specV1.Image,
  252. Labels: specV1.Labels,
  253. Envs: specV1.Envs,
  254. }
  255. if specV1.HasCpu {
  256. specV2.Cpu.Limit = specV1.Cpu.Limit
  257. specV2.Cpu.MaxLimit = specV1.Cpu.MaxLimit
  258. specV2.Cpu.Mask = specV1.Cpu.Mask
  259. }
  260. if specV1.HasMemory {
  261. specV2.Memory.Limit = specV1.Memory.Limit
  262. specV2.Memory.Reservation = specV1.Memory.Reservation
  263. specV2.Memory.SwapLimit = specV1.Memory.SwapLimit
  264. }
  265. if specV1.HasCustomMetrics {
  266. specV2.CustomMetrics = specV1.CustomMetrics
  267. }
  268. specV2.Aliases = aliases
  269. specV2.Namespace = namespace
  270. return specV2
  271. }