backend.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. package moby
  2. import (
  3. "context"
  4. "io"
  5. "github.com/docker/api/context/cloud"
  6. "github.com/docker/docker/api/types"
  7. "github.com/docker/docker/api/types/container"
  8. "github.com/docker/docker/client"
  9. "github.com/pkg/errors"
  10. "github.com/docker/api/backend"
  11. "github.com/docker/api/compose"
  12. "github.com/docker/api/containers"
  13. "github.com/docker/api/errdefs"
  14. )
  15. type mobyService struct {
  16. apiClient *client.Client
  17. }
  18. func init() {
  19. backend.Register("moby", "moby", func(ctx context.Context) (backend.Service, error) {
  20. return New()
  21. })
  22. }
  23. // New returns a moby backend implementation
  24. func New() (backend.Service, error) {
  25. apiClient, err := client.NewClientWithOpts(client.FromEnv)
  26. if err != nil {
  27. return nil, err
  28. }
  29. return &mobyService{
  30. apiClient,
  31. }, nil
  32. }
  33. func (ms *mobyService) ContainerService() containers.Service {
  34. return ms
  35. }
  36. func (ms *mobyService) ComposeService() compose.Service {
  37. return nil
  38. }
  39. func (ms *mobyService) CloudService() cloud.Service {
  40. return nil
  41. }
  42. func (ms *mobyService) List(ctx context.Context) ([]containers.Container, error) {
  43. css, err := ms.apiClient.ContainerList(ctx, types.ContainerListOptions{
  44. All: false,
  45. })
  46. if err != nil {
  47. return []containers.Container{}, err
  48. }
  49. var result []containers.Container
  50. for _, container := range css {
  51. result = append(result, containers.Container{
  52. ID: container.ID,
  53. Image: container.Image,
  54. Status: container.Status,
  55. Command: container.Command,
  56. Ports: getPorts(container.Ports),
  57. })
  58. }
  59. return result, nil
  60. }
  61. func (ms *mobyService) Run(ctx context.Context, r containers.ContainerConfig) error {
  62. create, err := ms.apiClient.ContainerCreate(ctx, &container.Config{
  63. Image: r.Image,
  64. Labels: r.Labels,
  65. }, nil, nil, r.ID)
  66. if err != nil {
  67. return err
  68. }
  69. return ms.apiClient.ContainerStart(ctx, create.ID, types.ContainerStartOptions{})
  70. }
  71. func (ms *mobyService) Exec(ctx context.Context, name string, command string, reader io.Reader, writer io.Writer) error {
  72. cec, err := ms.apiClient.ContainerExecCreate(ctx, name, types.ExecConfig{
  73. Cmd: []string{command},
  74. Tty: true,
  75. AttachStderr: true,
  76. AttachStdin: true,
  77. AttachStdout: true,
  78. })
  79. if err != nil {
  80. return err
  81. }
  82. resp, err := ms.apiClient.ContainerExecAttach(ctx, cec.ID, types.ExecStartCheck{})
  83. if err != nil {
  84. return err
  85. }
  86. defer resp.Close()
  87. readChannel := make(chan error, 10)
  88. writeChannel := make(chan error, 10)
  89. go func() {
  90. _, err := io.Copy(writer, resp.Reader)
  91. readChannel <- err
  92. }()
  93. go func() {
  94. _, err := io.Copy(resp.Conn, reader)
  95. writeChannel <- err
  96. }()
  97. for {
  98. select {
  99. case err := <-readChannel:
  100. return err
  101. case err := <-writeChannel:
  102. return err
  103. }
  104. }
  105. }
  106. func (ms *mobyService) Logs(ctx context.Context, containerName string, request containers.LogsRequest) error {
  107. r, err := ms.apiClient.ContainerLogs(ctx, containerName, types.ContainerLogsOptions{
  108. ShowStdout: true,
  109. ShowStderr: true,
  110. })
  111. if err != nil {
  112. return err
  113. }
  114. _, err = io.Copy(request.Writer, r)
  115. return err
  116. }
  117. func (ms *mobyService) Delete(ctx context.Context, containerID string, force bool) error {
  118. err := ms.apiClient.ContainerRemove(ctx, containerID, types.ContainerRemoveOptions{
  119. Force: force,
  120. })
  121. if client.IsErrNotFound(err) {
  122. return errors.Wrapf(errdefs.ErrNotFound, "container %q", containerID)
  123. }
  124. return err
  125. }
  126. func getPorts(ports []types.Port) []containers.Port {
  127. result := []containers.Port{}
  128. for _, port := range ports {
  129. result = append(result, containers.Port{
  130. ContainerPort: uint32(port.PrivatePort),
  131. HostPort: uint32(port.PublicPort),
  132. HostIP: port.IP,
  133. Protocol: port.Type,
  134. })
  135. }
  136. return result
  137. }