helpers.go 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. /*
  2. Copyright 2016 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 kuberuntime
  14. import (
  15. "fmt"
  16. "path/filepath"
  17. "strconv"
  18. "strings"
  19. "k8s.io/api/core/v1"
  20. "k8s.io/apimachinery/pkg/types"
  21. utilfeature "k8s.io/apiserver/pkg/util/feature"
  22. runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1alpha2"
  23. "k8s.io/klog"
  24. "k8s.io/kubernetes/pkg/features"
  25. kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
  26. )
  27. type podsByID []*kubecontainer.Pod
  28. func (b podsByID) Len() int { return len(b) }
  29. func (b podsByID) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
  30. func (b podsByID) Less(i, j int) bool { return b[i].ID < b[j].ID }
  31. type containersByID []*kubecontainer.Container
  32. func (b containersByID) Len() int { return len(b) }
  33. func (b containersByID) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
  34. func (b containersByID) Less(i, j int) bool { return b[i].ID.ID < b[j].ID.ID }
  35. // Newest first.
  36. type podSandboxByCreated []*runtimeapi.PodSandbox
  37. func (p podSandboxByCreated) Len() int { return len(p) }
  38. func (p podSandboxByCreated) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
  39. func (p podSandboxByCreated) Less(i, j int) bool { return p[i].CreatedAt > p[j].CreatedAt }
  40. type containerStatusByCreated []*kubecontainer.ContainerStatus
  41. func (c containerStatusByCreated) Len() int { return len(c) }
  42. func (c containerStatusByCreated) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
  43. func (c containerStatusByCreated) Less(i, j int) bool { return c[i].CreatedAt.After(c[j].CreatedAt) }
  44. // toKubeContainerState converts runtimeapi.ContainerState to kubecontainer.ContainerState.
  45. func toKubeContainerState(state runtimeapi.ContainerState) kubecontainer.ContainerState {
  46. switch state {
  47. case runtimeapi.ContainerState_CONTAINER_CREATED:
  48. return kubecontainer.ContainerStateCreated
  49. case runtimeapi.ContainerState_CONTAINER_RUNNING:
  50. return kubecontainer.ContainerStateRunning
  51. case runtimeapi.ContainerState_CONTAINER_EXITED:
  52. return kubecontainer.ContainerStateExited
  53. case runtimeapi.ContainerState_CONTAINER_UNKNOWN:
  54. return kubecontainer.ContainerStateUnknown
  55. }
  56. return kubecontainer.ContainerStateUnknown
  57. }
  58. // toRuntimeProtocol converts v1.Protocol to runtimeapi.Protocol.
  59. func toRuntimeProtocol(protocol v1.Protocol) runtimeapi.Protocol {
  60. switch protocol {
  61. case v1.ProtocolTCP:
  62. return runtimeapi.Protocol_TCP
  63. case v1.ProtocolUDP:
  64. return runtimeapi.Protocol_UDP
  65. case v1.ProtocolSCTP:
  66. return runtimeapi.Protocol_SCTP
  67. }
  68. klog.Warningf("Unknown protocol %q: defaulting to TCP", protocol)
  69. return runtimeapi.Protocol_TCP
  70. }
  71. // toKubeContainer converts runtimeapi.Container to kubecontainer.Container.
  72. func (m *kubeGenericRuntimeManager) toKubeContainer(c *runtimeapi.Container) (*kubecontainer.Container, error) {
  73. if c == nil || c.Id == "" || c.Image == nil {
  74. return nil, fmt.Errorf("unable to convert a nil pointer to a runtime container")
  75. }
  76. annotatedInfo := getContainerInfoFromAnnotations(c.Annotations)
  77. return &kubecontainer.Container{
  78. ID: kubecontainer.ContainerID{Type: m.runtimeName, ID: c.Id},
  79. Name: c.GetMetadata().GetName(),
  80. ImageID: c.ImageRef,
  81. Image: c.Image.Image,
  82. Hash: annotatedInfo.Hash,
  83. State: toKubeContainerState(c.State),
  84. }, nil
  85. }
  86. // sandboxToKubeContainer converts runtimeapi.PodSandbox to kubecontainer.Container.
  87. // This is only needed because we need to return sandboxes as if they were
  88. // kubecontainer.Containers to avoid substantial changes to PLEG.
  89. // TODO: Remove this once it becomes obsolete.
  90. func (m *kubeGenericRuntimeManager) sandboxToKubeContainer(s *runtimeapi.PodSandbox) (*kubecontainer.Container, error) {
  91. if s == nil || s.Id == "" {
  92. return nil, fmt.Errorf("unable to convert a nil pointer to a runtime container")
  93. }
  94. return &kubecontainer.Container{
  95. ID: kubecontainer.ContainerID{Type: m.runtimeName, ID: s.Id},
  96. State: kubecontainer.SandboxToContainerState(s.State),
  97. }, nil
  98. }
  99. // getImageUser gets uid or user name that will run the command(s) from image. The function
  100. // guarantees that only one of them is set.
  101. func (m *kubeGenericRuntimeManager) getImageUser(image string) (*int64, string, error) {
  102. imageStatus, err := m.imageService.ImageStatus(&runtimeapi.ImageSpec{Image: image})
  103. if err != nil {
  104. return nil, "", err
  105. }
  106. if imageStatus != nil {
  107. if imageStatus.Uid != nil {
  108. return &imageStatus.GetUid().Value, "", nil
  109. }
  110. if imageStatus.Username != "" {
  111. return nil, imageStatus.Username, nil
  112. }
  113. }
  114. // If non of them is set, treat it as root.
  115. return new(int64), "", nil
  116. }
  117. // isInitContainerFailed returns true if container has exited and exitcode is not zero
  118. // or is in unknown state.
  119. func isInitContainerFailed(status *kubecontainer.ContainerStatus) bool {
  120. if status.State == kubecontainer.ContainerStateExited && status.ExitCode != 0 {
  121. return true
  122. }
  123. if status.State == kubecontainer.ContainerStateUnknown {
  124. return true
  125. }
  126. return false
  127. }
  128. // getStableKey generates a key (string) to uniquely identify a
  129. // (pod, container) tuple. The key should include the content of the
  130. // container, so that any change to the container generates a new key.
  131. func getStableKey(pod *v1.Pod, container *v1.Container) string {
  132. hash := strconv.FormatUint(kubecontainer.HashContainer(container), 16)
  133. return fmt.Sprintf("%s_%s_%s_%s_%s", pod.Name, pod.Namespace, string(pod.UID), container.Name, hash)
  134. }
  135. // logPathDelimiter is the delimiter used in the log path.
  136. const logPathDelimiter = "_"
  137. // buildContainerLogsPath builds log path for container relative to pod logs directory.
  138. func buildContainerLogsPath(containerName string, restartCount int) string {
  139. return filepath.Join(containerName, fmt.Sprintf("%d.log", restartCount))
  140. }
  141. // BuildContainerLogsDirectory builds absolute log directory path for a container in pod.
  142. func BuildContainerLogsDirectory(podNamespace, podName string, podUID types.UID, containerName string) string {
  143. return filepath.Join(BuildPodLogsDirectory(podNamespace, podName, podUID), containerName)
  144. }
  145. // BuildPodLogsDirectory builds absolute log directory path for a pod sandbox.
  146. func BuildPodLogsDirectory(podNamespace, podName string, podUID types.UID) string {
  147. return filepath.Join(podLogsRootDirectory, strings.Join([]string{podNamespace, podName,
  148. string(podUID)}, logPathDelimiter))
  149. }
  150. // parsePodUIDFromLogsDirectory parses pod logs directory name and returns the pod UID.
  151. // It supports both the old pod log directory /var/log/pods/UID, and the new pod log
  152. // directory /var/log/pods/NAMESPACE_NAME_UID.
  153. func parsePodUIDFromLogsDirectory(name string) types.UID {
  154. parts := strings.Split(name, logPathDelimiter)
  155. return types.UID(parts[len(parts)-1])
  156. }
  157. // toKubeRuntimeStatus converts the runtimeapi.RuntimeStatus to kubecontainer.RuntimeStatus.
  158. func toKubeRuntimeStatus(status *runtimeapi.RuntimeStatus) *kubecontainer.RuntimeStatus {
  159. conditions := []kubecontainer.RuntimeCondition{}
  160. for _, c := range status.GetConditions() {
  161. conditions = append(conditions, kubecontainer.RuntimeCondition{
  162. Type: kubecontainer.RuntimeConditionType(c.Type),
  163. Status: c.Status,
  164. Reason: c.Reason,
  165. Message: c.Message,
  166. })
  167. }
  168. return &kubecontainer.RuntimeStatus{Conditions: conditions}
  169. }
  170. // getSeccompProfileFromAnnotations gets seccomp profile from annotations.
  171. // It gets pod's profile if containerName is empty.
  172. func (m *kubeGenericRuntimeManager) getSeccompProfileFromAnnotations(annotations map[string]string, containerName string) string {
  173. // try the pod profile.
  174. profile, profileOK := annotations[v1.SeccompPodAnnotationKey]
  175. if containerName != "" {
  176. // try the container profile.
  177. cProfile, cProfileOK := annotations[v1.SeccompContainerAnnotationKeyPrefix+containerName]
  178. if cProfileOK {
  179. profile = cProfile
  180. profileOK = cProfileOK
  181. }
  182. }
  183. if !profileOK {
  184. return ""
  185. }
  186. if strings.HasPrefix(profile, "localhost/") {
  187. name := strings.TrimPrefix(profile, "localhost/")
  188. fname := filepath.Join(m.seccompProfileRoot, filepath.FromSlash(name))
  189. return "localhost/" + fname
  190. }
  191. return profile
  192. }
  193. func ipcNamespaceForPod(pod *v1.Pod) runtimeapi.NamespaceMode {
  194. if pod != nil && pod.Spec.HostIPC {
  195. return runtimeapi.NamespaceMode_NODE
  196. }
  197. return runtimeapi.NamespaceMode_POD
  198. }
  199. func networkNamespaceForPod(pod *v1.Pod) runtimeapi.NamespaceMode {
  200. if pod != nil && pod.Spec.HostNetwork {
  201. return runtimeapi.NamespaceMode_NODE
  202. }
  203. return runtimeapi.NamespaceMode_POD
  204. }
  205. func pidNamespaceForPod(pod *v1.Pod) runtimeapi.NamespaceMode {
  206. if pod != nil {
  207. if pod.Spec.HostPID {
  208. return runtimeapi.NamespaceMode_NODE
  209. }
  210. if utilfeature.DefaultFeatureGate.Enabled(features.PodShareProcessNamespace) && pod.Spec.ShareProcessNamespace != nil && *pod.Spec.ShareProcessNamespace {
  211. return runtimeapi.NamespaceMode_POD
  212. }
  213. }
  214. // Note that PID does not default to the zero value for v1.Pod
  215. return runtimeapi.NamespaceMode_CONTAINER
  216. }
  217. // namespacesForPod returns the runtimeapi.NamespaceOption for a given pod.
  218. // An empty or nil pod can be used to get the namespace defaults for v1.Pod.
  219. func namespacesForPod(pod *v1.Pod) *runtimeapi.NamespaceOption {
  220. return &runtimeapi.NamespaceOption{
  221. Ipc: ipcNamespaceForPod(pod),
  222. Network: networkNamespaceForPod(pod),
  223. Pid: pidNamespaceForPod(pod),
  224. }
  225. }