docker.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. // Copyright 2016 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. // Provides global docker information.
  15. package docker
  16. import (
  17. "fmt"
  18. "regexp"
  19. "strconv"
  20. dockertypes "github.com/docker/docker/api/types"
  21. "golang.org/x/net/context"
  22. "time"
  23. "github.com/google/cadvisor/info/v1"
  24. "github.com/google/cadvisor/machine"
  25. )
  26. var dockerTimeout = 10 * time.Second
  27. func defaultContext() context.Context {
  28. ctx, _ := context.WithTimeout(context.Background(), dockerTimeout)
  29. return ctx
  30. }
  31. func SetTimeout(timeout time.Duration) {
  32. dockerTimeout = timeout
  33. }
  34. func Status() (v1.DockerStatus, error) {
  35. return StatusWithContext(defaultContext())
  36. }
  37. func StatusWithContext(ctx context.Context) (v1.DockerStatus, error) {
  38. client, err := Client()
  39. if err != nil {
  40. return v1.DockerStatus{}, fmt.Errorf("unable to communicate with docker daemon: %v", err)
  41. }
  42. dockerInfo, err := client.Info(ctx)
  43. if err != nil {
  44. return v1.DockerStatus{}, err
  45. }
  46. return StatusFromDockerInfo(dockerInfo)
  47. }
  48. func StatusFromDockerInfo(dockerInfo dockertypes.Info) (v1.DockerStatus, error) {
  49. out := v1.DockerStatus{}
  50. out.KernelVersion = machine.KernelVersion()
  51. out.OS = dockerInfo.OperatingSystem
  52. out.Hostname = dockerInfo.Name
  53. out.RootDir = dockerInfo.DockerRootDir
  54. out.Driver = dockerInfo.Driver
  55. out.NumImages = dockerInfo.Images
  56. out.NumContainers = dockerInfo.Containers
  57. out.DriverStatus = make(map[string]string, len(dockerInfo.DriverStatus))
  58. for _, v := range dockerInfo.DriverStatus {
  59. out.DriverStatus[v[0]] = v[1]
  60. }
  61. var err error
  62. ver, err := VersionString()
  63. if err != nil {
  64. return out, err
  65. }
  66. out.Version = ver
  67. ver, err = APIVersionString()
  68. if err != nil {
  69. return out, err
  70. }
  71. out.APIVersion = ver
  72. return out, nil
  73. }
  74. func Images() ([]v1.DockerImage, error) {
  75. client, err := Client()
  76. if err != nil {
  77. return nil, fmt.Errorf("unable to communicate with docker daemon: %v", err)
  78. }
  79. images, err := client.ImageList(defaultContext(), dockertypes.ImageListOptions{All: false})
  80. if err != nil {
  81. return nil, err
  82. }
  83. out := []v1.DockerImage{}
  84. const unknownTag = "<none>:<none>"
  85. for _, image := range images {
  86. if len(image.RepoTags) == 1 && image.RepoTags[0] == unknownTag {
  87. // images with repo or tags are uninteresting.
  88. continue
  89. }
  90. di := v1.DockerImage{
  91. ID: image.ID,
  92. RepoTags: image.RepoTags,
  93. Created: image.Created,
  94. VirtualSize: image.VirtualSize,
  95. Size: image.Size,
  96. }
  97. out = append(out, di)
  98. }
  99. return out, nil
  100. }
  101. // Checks whether the dockerInfo reflects a valid docker setup, and returns it if it does, or an
  102. // error otherwise.
  103. func ValidateInfo() (*dockertypes.Info, error) {
  104. client, err := Client()
  105. if err != nil {
  106. return nil, fmt.Errorf("unable to communicate with docker daemon: %v", err)
  107. }
  108. dockerInfo, err := client.Info(defaultContext())
  109. if err != nil {
  110. return nil, fmt.Errorf("failed to detect Docker info: %v", err)
  111. }
  112. // Fall back to version API if ServerVersion is not set in info.
  113. if dockerInfo.ServerVersion == "" {
  114. version, err := client.ServerVersion(defaultContext())
  115. if err != nil {
  116. return nil, fmt.Errorf("unable to get docker version: %v", err)
  117. }
  118. dockerInfo.ServerVersion = version.Version
  119. }
  120. version, err := parseVersion(dockerInfo.ServerVersion, version_re, 3)
  121. if err != nil {
  122. return nil, err
  123. }
  124. if version[0] < 1 {
  125. return nil, fmt.Errorf("cAdvisor requires docker version %v or above but we have found version %v reported as %q", []int{1, 0, 0}, version, dockerInfo.ServerVersion)
  126. }
  127. if dockerInfo.Driver == "" {
  128. return nil, fmt.Errorf("failed to find docker storage driver")
  129. }
  130. return &dockerInfo, nil
  131. }
  132. func Version() ([]int, error) {
  133. ver, err := VersionString()
  134. if err != nil {
  135. return nil, err
  136. }
  137. return parseVersion(ver, version_re, 3)
  138. }
  139. func APIVersion() ([]int, error) {
  140. ver, err := APIVersionString()
  141. if err != nil {
  142. return nil, err
  143. }
  144. return parseVersion(ver, apiversion_re, 2)
  145. }
  146. func VersionString() (string, error) {
  147. docker_version := "Unknown"
  148. client, err := Client()
  149. if err == nil {
  150. version, err := client.ServerVersion(defaultContext())
  151. if err == nil {
  152. docker_version = version.Version
  153. }
  154. }
  155. return docker_version, err
  156. }
  157. func APIVersionString() (string, error) {
  158. docker_api_version := "Unknown"
  159. client, err := Client()
  160. if err == nil {
  161. version, err := client.ServerVersion(defaultContext())
  162. if err == nil {
  163. docker_api_version = version.APIVersion
  164. }
  165. }
  166. return docker_api_version, err
  167. }
  168. func parseVersion(version_string string, regex *regexp.Regexp, length int) ([]int, error) {
  169. matches := regex.FindAllStringSubmatch(version_string, -1)
  170. if len(matches) != 1 {
  171. return nil, fmt.Errorf("version string \"%v\" doesn't match expected regular expression: \"%v\"", version_string, regex.String())
  172. }
  173. version_string_array := matches[0][1:]
  174. version_array := make([]int, length)
  175. for index, version_str := range version_string_array {
  176. version, err := strconv.Atoi(version_str)
  177. if err != nil {
  178. return nil, fmt.Errorf("error while parsing \"%v\" in \"%v\"", version_str, version_string)
  179. }
  180. version_array[index] = version
  181. }
  182. return version_array, nil
  183. }