client.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. // Copyright 2019 Yunion
  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 containerd
  15. import (
  16. "context"
  17. "fmt"
  18. "strconv"
  19. "time"
  20. "github.com/containerd/containerd"
  21. "github.com/containerd/containerd/errdefs"
  22. "github.com/containerd/containerd/runtime/restart"
  23. "github.com/containerd/typeurl"
  24. "github.com/opencontainers/runtime-spec/specs-go"
  25. "yunion.io/x/log"
  26. "yunion.io/x/pkg/errors"
  27. )
  28. func init() {
  29. const prefix = "types.containerd.io"
  30. // register TypeUrls for commonly marshaled external types
  31. major := strconv.Itoa(specs.VersionMajor)
  32. typeurl.Register(&specs.Spec{}, prefix, "opencontainers/runtime-spec", major, "Spec")
  33. typeurl.Register(&specs.Process{}, prefix, "opencontainers/runtime-spec", major, "Process")
  34. typeurl.Register(&specs.LinuxResources{}, prefix, "opencontainers/runtime-spec", major, "LinuxResources")
  35. typeurl.Register(&specs.WindowsResources{}, prefix, "opencontainers/runtime-spec", major, "WindowsResources")
  36. }
  37. // NewClient 创建 containerd 客户端
  38. // 参考 nerdctl 的实现方式,使用 containerd.Client
  39. func NewClient(ctx context.Context, address, namespace string) (*containerd.Client, error) {
  40. // 使用 containerd.New 创建客户端,参考 nerdctl 实现
  41. client, err := containerd.New(address,
  42. containerd.WithDefaultNamespace(namespace),
  43. )
  44. if err != nil {
  45. return nil, errors.Wrapf(err, "create containerd client at %s", address)
  46. }
  47. return client, nil
  48. }
  49. type ProcessStatus string
  50. const (
  51. ProcessStatusCreated ProcessStatus = "created"
  52. ProcessStatusRunning ProcessStatus = "running"
  53. ProcessStatusStopped ProcessStatus = "stopped"
  54. ProcessStatusUnknown ProcessStatus = "unknown"
  55. ProcessStatusRestarting ProcessStatus = "restarting"
  56. )
  57. func ContainerStatus(ctx context.Context, c containerd.Container) ProcessStatus {
  58. ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
  59. defer cancel()
  60. task, err := c.Task(ctx, nil)
  61. if err != nil {
  62. if errdefs.IsNotFound(err) {
  63. return ProcessStatusCreated
  64. }
  65. log.Warningf("failed to get task for container %s: %v", c.ID(), err)
  66. return ProcessStatusUnknown
  67. }
  68. status, err := task.Status(ctx)
  69. if err != nil {
  70. log.Warningf("failed to get status for task %s: %v", task.ID(), err)
  71. return ProcessStatusUnknown
  72. }
  73. labels, err := c.Labels(ctx)
  74. if err != nil {
  75. log.Warningf("failed to get labels for container %s: %v", c.ID(), err)
  76. return ProcessStatusUnknown
  77. }
  78. switch s := status.Status; s {
  79. case containerd.Stopped:
  80. if labels[restart.StatusLabel] == string(containerd.Running) && restart.Reconcile(status, labels) {
  81. s := fmt.Sprintf("Restarting (%d) %v", status.ExitStatus, status.ExitTime)
  82. log.Infof("container %s is restarting: %s", c.ID(), s)
  83. return ProcessStatusRestarting
  84. }
  85. return ProcessStatusStopped
  86. case containerd.Running:
  87. return ProcessStatusRunning
  88. }
  89. return ProcessStatus(status.Status)
  90. }