container.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. package metabase
  2. import (
  3. "bufio"
  4. "context"
  5. "fmt"
  6. "runtime"
  7. "time"
  8. "github.com/docker/docker/api/types"
  9. "github.com/docker/docker/api/types/container"
  10. "github.com/docker/docker/api/types/mount"
  11. "github.com/docker/docker/client"
  12. "github.com/docker/go-connections/nat"
  13. log "github.com/sirupsen/logrus"
  14. )
  15. type Container struct {
  16. ListenAddr string
  17. ListenPort string
  18. SharedFolder string
  19. Image string
  20. Name string
  21. ID string
  22. CLI *client.Client
  23. MBDBUri string
  24. DockerGroupID string
  25. }
  26. func NewContainer(listenAddr string, listenPort string, sharedFolder string, containerName string, image string, mbDBURI string, dockerGroupID string) (*Container, error) {
  27. cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
  28. if err != nil {
  29. return nil, fmt.Errorf("failed to create docker client : %s", err)
  30. }
  31. return &Container{
  32. ListenAddr: listenAddr,
  33. ListenPort: listenPort,
  34. SharedFolder: sharedFolder,
  35. Image: image,
  36. Name: containerName,
  37. CLI: cli,
  38. MBDBUri: mbDBURI,
  39. DockerGroupID: dockerGroupID,
  40. }, nil
  41. }
  42. func (c *Container) Create() error {
  43. ctx := context.Background()
  44. log.Printf("Pulling docker image %s", c.Image)
  45. reader, err := c.CLI.ImagePull(ctx, c.Image, types.ImagePullOptions{})
  46. if err != nil {
  47. return fmt.Errorf("failed to pull docker image : %s", err)
  48. }
  49. defer reader.Close()
  50. scanner := bufio.NewScanner(reader)
  51. for scanner.Scan() {
  52. fmt.Print(".")
  53. }
  54. if err := scanner.Err(); err != nil {
  55. return fmt.Errorf("failed to read imagepull reader: %s", err)
  56. }
  57. fmt.Print("\n")
  58. hostConfig := &container.HostConfig{
  59. PortBindings: nat.PortMap{
  60. "3000/tcp": []nat.PortBinding{
  61. {
  62. HostIP: c.ListenAddr,
  63. HostPort: c.ListenPort,
  64. },
  65. },
  66. },
  67. Mounts: []mount.Mount{
  68. {
  69. Type: mount.TypeBind,
  70. Source: c.SharedFolder,
  71. Target: containerSharedFolder,
  72. },
  73. },
  74. }
  75. env := []string{
  76. fmt.Sprintf("MB_DB_FILE=%s/metabase.db", containerSharedFolder),
  77. }
  78. if c.MBDBUri != "" {
  79. env = append(env, c.MBDBUri)
  80. }
  81. env = append(env, fmt.Sprintf("MGID=%s", c.DockerGroupID))
  82. dockerConfig := &container.Config{
  83. Image: c.Image,
  84. Tty: true,
  85. Env: env,
  86. }
  87. os := runtime.GOOS
  88. switch os {
  89. case "linux":
  90. case "windows", "darwin":
  91. return fmt.Errorf("Mac and Windows are not supported yet")
  92. default:
  93. return fmt.Errorf("OS '%s' is not supported", os)
  94. }
  95. log.Infof("creating container '%s'", c.Name)
  96. resp, err := c.CLI.ContainerCreate(ctx, dockerConfig, hostConfig, nil, nil, c.Name)
  97. if err != nil {
  98. return fmt.Errorf("failed to create container : %s", err)
  99. }
  100. c.ID = resp.ID
  101. return nil
  102. }
  103. func (c *Container) Start() error {
  104. ctx := context.Background()
  105. if err := c.CLI.ContainerStart(ctx, c.Name, types.ContainerStartOptions{}); err != nil {
  106. return fmt.Errorf("failed while starting %s : %s", c.ID, err)
  107. }
  108. return nil
  109. }
  110. func StartContainer(name string) error {
  111. cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
  112. if err != nil {
  113. return fmt.Errorf("failed to create docker client : %s", err)
  114. }
  115. ctx := context.Background()
  116. if err := cli.ContainerStart(ctx, name, types.ContainerStartOptions{}); err != nil {
  117. return fmt.Errorf("failed while starting %s : %s", name, err)
  118. }
  119. return nil
  120. }
  121. func StopContainer(name string) error {
  122. cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
  123. if err != nil {
  124. return fmt.Errorf("failed to create docker client : %s", err)
  125. }
  126. ctx := context.Background()
  127. var to time.Duration = 20 * time.Second
  128. if err := cli.ContainerStop(ctx, name, &to); err != nil {
  129. return fmt.Errorf("failed while stopping %s : %s", name, err)
  130. }
  131. log.Printf("container stopped successfully")
  132. return nil
  133. }
  134. func RemoveContainer(name string) error {
  135. cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
  136. if err != nil {
  137. return fmt.Errorf("failed to create docker client : %s", err)
  138. }
  139. ctx := context.Background()
  140. log.Printf("Removing docker metabase %s", name)
  141. if err := cli.ContainerRemove(ctx, name, types.ContainerRemoveOptions{}); err != nil {
  142. return fmt.Errorf("failed remove container %s : %s", name, err)
  143. }
  144. return nil
  145. }
  146. func RemoveImageContainer() error {
  147. cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
  148. if err != nil {
  149. return fmt.Errorf("failed to create docker client : %s", err)
  150. }
  151. ctx := context.Background()
  152. log.Printf("Removing docker image '%s'", metabaseImage)
  153. if _, err := cli.ImageRemove(ctx, metabaseImage, types.ImageRemoveOptions{}); err != nil {
  154. return fmt.Errorf("failed remove image container %s : %s", metabaseImage, err)
  155. }
  156. return nil
  157. }
  158. func IsContainerExist(name string) bool {
  159. cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
  160. if err != nil {
  161. log.Fatalf("failed to create docker client : %s", err)
  162. }
  163. ctx := context.Background()
  164. if _, err := cli.ContainerInspect(ctx, name); err != nil {
  165. return false
  166. }
  167. return true
  168. }