labels.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. /*
  2. Copyright 2015 The Kubernetes Authors.
  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. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package dockertools
  14. import (
  15. "encoding/json"
  16. "strconv"
  17. "github.com/golang/glog"
  18. "k8s.io/kubernetes/pkg/api"
  19. kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
  20. "k8s.io/kubernetes/pkg/kubelet/custommetrics"
  21. "k8s.io/kubernetes/pkg/kubelet/types"
  22. "k8s.io/kubernetes/pkg/kubelet/util/format"
  23. "k8s.io/kubernetes/pkg/runtime"
  24. kubetypes "k8s.io/kubernetes/pkg/types"
  25. )
  26. // This file contains all docker label related constants and functions, including:
  27. // * label setters and getters
  28. // * label filters (maybe in the future)
  29. const (
  30. kubernetesPodDeletionGracePeriodLabel = "io.kubernetes.pod.deletionGracePeriod"
  31. kubernetesPodTerminationGracePeriodLabel = "io.kubernetes.pod.terminationGracePeriod"
  32. kubernetesContainerHashLabel = "io.kubernetes.container.hash"
  33. kubernetesContainerRestartCountLabel = "io.kubernetes.container.restartCount"
  34. kubernetesContainerTerminationMessagePathLabel = "io.kubernetes.container.terminationMessagePath"
  35. kubernetesContainerPreStopHandlerLabel = "io.kubernetes.container.preStopHandler"
  36. kubernetesContainerPortsLabel = "io.kubernetes.container.ports" // Added in 1.4
  37. // TODO(random-liu): Keep this for old containers, remove this when we drop support for v1.1.
  38. kubernetesPodLabel = "io.kubernetes.pod.data"
  39. cadvisorPrometheusMetricsLabel = "io.cadvisor.metric.prometheus"
  40. )
  41. // Container information which has been labelled on each docker container
  42. // TODO(random-liu): The type of Hash should be compliance with kubelet container status.
  43. type labelledContainerInfo struct {
  44. PodName string
  45. PodNamespace string
  46. PodUID kubetypes.UID
  47. PodDeletionGracePeriod *int64
  48. PodTerminationGracePeriod *int64
  49. Name string
  50. Hash string
  51. RestartCount int
  52. TerminationMessagePath string
  53. PreStopHandler *api.Handler
  54. Ports []api.ContainerPort
  55. }
  56. func newLabels(container *api.Container, pod *api.Pod, restartCount int, enableCustomMetrics bool) map[string]string {
  57. labels := map[string]string{}
  58. labels[types.KubernetesPodNameLabel] = pod.Name
  59. labels[types.KubernetesPodNamespaceLabel] = pod.Namespace
  60. labels[types.KubernetesPodUIDLabel] = string(pod.UID)
  61. if pod.DeletionGracePeriodSeconds != nil {
  62. labels[kubernetesPodDeletionGracePeriodLabel] = strconv.FormatInt(*pod.DeletionGracePeriodSeconds, 10)
  63. }
  64. if pod.Spec.TerminationGracePeriodSeconds != nil {
  65. labels[kubernetesPodTerminationGracePeriodLabel] = strconv.FormatInt(*pod.Spec.TerminationGracePeriodSeconds, 10)
  66. }
  67. labels[types.KubernetesContainerNameLabel] = container.Name
  68. labels[kubernetesContainerHashLabel] = strconv.FormatUint(kubecontainer.HashContainer(container), 16)
  69. labels[kubernetesContainerRestartCountLabel] = strconv.Itoa(restartCount)
  70. labels[kubernetesContainerTerminationMessagePathLabel] = container.TerminationMessagePath
  71. if container.Lifecycle != nil && container.Lifecycle.PreStop != nil {
  72. // Using json enconding so that the PreStop handler object is readable after writing as a label
  73. rawPreStop, err := json.Marshal(container.Lifecycle.PreStop)
  74. if err != nil {
  75. glog.Errorf("Unable to marshal lifecycle PreStop handler for container %q of pod %q: %v", container.Name, format.Pod(pod), err)
  76. } else {
  77. labels[kubernetesContainerPreStopHandlerLabel] = string(rawPreStop)
  78. }
  79. }
  80. if len(container.Ports) > 0 {
  81. rawContainerPorts, err := json.Marshal(container.Ports)
  82. if err != nil {
  83. glog.Errorf("Unable to marshal container ports for container %q for pod %q: %v", container.Name, format.Pod(pod), err)
  84. } else {
  85. labels[kubernetesContainerPortsLabel] = string(rawContainerPorts)
  86. }
  87. }
  88. if enableCustomMetrics {
  89. path, err := custommetrics.GetCAdvisorCustomMetricsDefinitionPath(container)
  90. if path != nil && err == nil {
  91. labels[cadvisorPrometheusMetricsLabel] = *path
  92. }
  93. }
  94. return labels
  95. }
  96. func getContainerInfoFromLabel(labels map[string]string) *labelledContainerInfo {
  97. var err error
  98. containerInfo := &labelledContainerInfo{
  99. PodName: getStringValueFromLabel(labels, types.KubernetesPodNameLabel),
  100. PodNamespace: getStringValueFromLabel(labels, types.KubernetesPodNamespaceLabel),
  101. PodUID: kubetypes.UID(getStringValueFromLabel(labels, types.KubernetesPodUIDLabel)),
  102. Name: getStringValueFromLabel(labels, types.KubernetesContainerNameLabel),
  103. Hash: getStringValueFromLabel(labels, kubernetesContainerHashLabel),
  104. TerminationMessagePath: getStringValueFromLabel(labels, kubernetesContainerTerminationMessagePathLabel),
  105. }
  106. if containerInfo.RestartCount, err = getIntValueFromLabel(labels, kubernetesContainerRestartCountLabel); err != nil {
  107. logError(containerInfo, kubernetesContainerRestartCountLabel, err)
  108. }
  109. if containerInfo.PodDeletionGracePeriod, err = getInt64PointerFromLabel(labels, kubernetesPodDeletionGracePeriodLabel); err != nil {
  110. logError(containerInfo, kubernetesPodDeletionGracePeriodLabel, err)
  111. }
  112. if containerInfo.PodTerminationGracePeriod, err = getInt64PointerFromLabel(labels, kubernetesPodTerminationGracePeriodLabel); err != nil {
  113. logError(containerInfo, kubernetesPodTerminationGracePeriodLabel, err)
  114. }
  115. preStopHandler := &api.Handler{}
  116. if found, err := getJsonObjectFromLabel(labels, kubernetesContainerPreStopHandlerLabel, preStopHandler); err != nil {
  117. logError(containerInfo, kubernetesContainerPreStopHandlerLabel, err)
  118. } else if found {
  119. containerInfo.PreStopHandler = preStopHandler
  120. }
  121. containerPorts := []api.ContainerPort{}
  122. if found, err := getJsonObjectFromLabel(labels, kubernetesContainerPortsLabel, &containerPorts); err != nil {
  123. logError(containerInfo, kubernetesContainerPortsLabel, err)
  124. } else if found {
  125. containerInfo.Ports = containerPorts
  126. }
  127. supplyContainerInfoWithOldLabel(labels, containerInfo)
  128. return containerInfo
  129. }
  130. func getStringValueFromLabel(labels map[string]string, label string) string {
  131. if value, found := labels[label]; found {
  132. return value
  133. }
  134. // Do not report error, because there should be many old containers without label now.
  135. glog.V(3).Infof("Container doesn't have label %s, it may be an old or invalid container", label)
  136. // Return empty string "" for these containers, the caller will get value by other ways.
  137. return ""
  138. }
  139. func getIntValueFromLabel(labels map[string]string, label string) (int, error) {
  140. if strValue, found := labels[label]; found {
  141. intValue, err := strconv.Atoi(strValue)
  142. if err != nil {
  143. // This really should not happen. Just set value to 0 to handle this abnormal case
  144. return 0, err
  145. }
  146. return intValue, nil
  147. }
  148. // Do not report error, because there should be many old containers without label now.
  149. glog.V(3).Infof("Container doesn't have label %s, it may be an old or invalid container", label)
  150. // Just set the value to 0
  151. return 0, nil
  152. }
  153. func getInt64PointerFromLabel(labels map[string]string, label string) (*int64, error) {
  154. if strValue, found := labels[label]; found {
  155. int64Value, err := strconv.ParseInt(strValue, 10, 64)
  156. if err != nil {
  157. return nil, err
  158. }
  159. return &int64Value, nil
  160. }
  161. // Because it's normal that a container has no PodDeletionGracePeriod and PodTerminationGracePeriod label,
  162. // don't report any error here.
  163. return nil, nil
  164. }
  165. // getJsonObjectFromLabel returns a bool value indicating whether an object is found
  166. func getJsonObjectFromLabel(labels map[string]string, label string, value interface{}) (bool, error) {
  167. if strValue, found := labels[label]; found {
  168. err := json.Unmarshal([]byte(strValue), value)
  169. return found, err
  170. }
  171. // Because it's normal that a container has no PreStopHandler label, don't report any error here.
  172. return false, nil
  173. }
  174. // The label kubernetesPodLabel is added a long time ago (#7421), it serialized the whole api.Pod to a docker label.
  175. // We want to remove this label because it serialized too much useless information. However kubelet may still work
  176. // with old containers which only have this label for a long time until we completely deprecate the old label.
  177. // Before that to ensure correctness we have to supply information with the old labels when newly added labels
  178. // are not available.
  179. // TODO(random-liu): Remove this function when we can completely remove label kubernetesPodLabel, probably after
  180. // dropping support for v1.1.
  181. func supplyContainerInfoWithOldLabel(labels map[string]string, containerInfo *labelledContainerInfo) {
  182. // Get api.Pod from old label
  183. var pod *api.Pod
  184. data, found := labels[kubernetesPodLabel]
  185. if !found {
  186. // Don't report any error here, because it's normal that a container has no pod label, especially
  187. // when we gradually deprecate the old label
  188. return
  189. }
  190. pod = &api.Pod{}
  191. if err := runtime.DecodeInto(api.Codecs.UniversalDecoder(), []byte(data), pod); err != nil {
  192. // If the pod label can't be parsed, we should report an error
  193. logError(containerInfo, kubernetesPodLabel, err)
  194. return
  195. }
  196. if containerInfo.PodDeletionGracePeriod == nil {
  197. containerInfo.PodDeletionGracePeriod = pod.DeletionGracePeriodSeconds
  198. }
  199. if containerInfo.PodTerminationGracePeriod == nil {
  200. containerInfo.PodTerminationGracePeriod = pod.Spec.TerminationGracePeriodSeconds
  201. }
  202. // Get api.Container from api.Pod
  203. var container *api.Container
  204. for i := range pod.Spec.Containers {
  205. if pod.Spec.Containers[i].Name == containerInfo.Name {
  206. container = &pod.Spec.Containers[i]
  207. break
  208. }
  209. }
  210. if container == nil {
  211. glog.Errorf("Unable to find container %q in pod %q", containerInfo.Name, format.Pod(pod))
  212. return
  213. }
  214. if containerInfo.PreStopHandler == nil && container.Lifecycle != nil {
  215. containerInfo.PreStopHandler = container.Lifecycle.PreStop
  216. }
  217. }
  218. func logError(containerInfo *labelledContainerInfo, label string, err error) {
  219. glog.Errorf("Unable to get %q for container %q of pod %q: %v", label, containerInfo.Name,
  220. kubecontainer.BuildPodFullName(containerInfo.PodName, containerInfo.PodNamespace), err)
  221. }