Guest User

Dockertest package

a guest
Nov 19th, 2015
658
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. package dockertest
  2.  
  3. import (
  4.     "bytes"
  5.     "fmt"
  6.     "log"
  7.     "net"
  8.     "os"
  9.     "os/exec"
  10.     "strings"
  11.     "time"
  12.  
  13.     "github.com/fsouza/go-dockerclient"
  14. )
  15.  
  16. // StartMysql starts new docker container with MySQL running.
  17. //
  18. // It returns dsn, defer function and error if any.
  19. func StartMysql() (string, func(), error) {
  20.     client, err := docker.NewClientFromEnv()
  21.     if err != nil {
  22.         return "", nil, err
  23.     }
  24.     c, err := client.CreateContainer(CreateOptions())
  25.     if err != nil {
  26.         return "", nil, err
  27.     }
  28.     deferFn := func() {
  29.         if err := client.RemoveContainer(docker.RemoveContainerOptions{
  30.             ID:    c.ID,
  31.             Force: true,
  32.         }); err != nil {
  33.             log.Println("cannot remove container: %v", err)
  34.         }
  35.     }
  36.  
  37.     // VM IP is the IP of DockerMachine VM, if running (used in non-Linux OSes)
  38.     vm_ip := strings.TrimSpace(DockerMachineIP())
  39.     var nonLinux bool = (vm_ip != "")
  40.  
  41.     err = client.StartContainer(c.ID, StartOptions(nonLinux))
  42.     if err != nil {
  43.         deferFn()
  44.         return "", nil, err
  45.     }
  46.  
  47.     // wait for container to wake up
  48.     if err := waitStarted(client, c.ID, 5*time.Second); err != nil {
  49.         deferFn()
  50.         return "", nil, err
  51.     }
  52.     if c, err = client.InspectContainer(c.ID); err != nil {
  53.         deferFn()
  54.         return "", nil, err
  55.     }
  56.  
  57.     // determine IP address for MySQL
  58.     ip := ""
  59.     if vm_ip != "" {
  60.         ip = vm_ip
  61.     } else if c.NetworkSettings != nil {
  62.         ip = strings.TrimSpace(c.NetworkSettings.IPAddress)
  63.     }
  64.  
  65.     // wait MySQL to wake up
  66.     if err := waitReachable(ip+":3306", 5*time.Second); err != nil {
  67.         deferFn()
  68.         return "", nil, err
  69.     }
  70.  
  71.     return dsn(ip), deferFn, nil
  72. }
  73.  
  74. // dsn returns valid dsn to be used with mysql driver for the given ip.
  75. func dsn(ip string) string {
  76.     return fmt.Sprintf("root:@tcp(%s:3306)/mydb", ip)
  77. }
  78.  
  79. func CreateOptions() docker.CreateContainerOptions {
  80.     ports := make(map[docker.Port]struct{})
  81.     ports["3306"] = struct{}{}
  82.     opts := docker.CreateContainerOptions{
  83.         Config: &docker.Config{
  84.             Image:        "mydb_test",
  85.             ExposedPorts: ports,
  86.         },
  87.     }
  88.  
  89.     return opts
  90. }
  91.  
  92. func StartOptions(bindPorts bool) *docker.HostConfig {
  93.     port_binds := make(map[docker.Port][]docker.PortBinding)
  94.     if bindPorts {
  95.         port_binds["3306"] = []docker.PortBinding{
  96.             docker.PortBinding{HostPort: "3306"},
  97.         }
  98.     }
  99.     conf := docker.HostConfig{
  100.         PortBindings: port_binds,
  101.     }
  102.  
  103.     return &conf
  104. }
  105.  
  106. // waitReachable waits for hostport to became reachable for the maxWait time.
  107. func waitReachable(hostport string, maxWait time.Duration) error {
  108.     done := time.Now().Add(maxWait)
  109.     for time.Now().Before(done) {
  110.         c, err := net.Dial("tcp", hostport)
  111.         if err == nil {
  112.             c.Close()
  113.             return nil
  114.         }
  115.         time.Sleep(100 * time.Millisecond)
  116.     }
  117.     return fmt.Errorf("cannot connect %v for %v", hostport, maxWait)
  118. }
  119.  
  120. // waitStarted waits for container to start for the maxWait time.
  121. func waitStarted(client *docker.Client, id string, maxWait time.Duration) error {
  122.     done := time.Now().Add(maxWait)
  123.     for time.Now().Before(done) {
  124.         c, err := client.InspectContainer(id)
  125.         if err != nil {
  126.             break
  127.         }
  128.         if c.State.Running {
  129.             return nil
  130.         }
  131.         time.Sleep(100 * time.Millisecond)
  132.     }
  133.     return fmt.Errorf("cannot start container %s for %v", id, maxWait)
  134. }
  135.  
  136. // DockerMachineIP returns IP of docker-machine or boot2docker VM instance.
  137. //
  138. // If docker-machine or boot2docker is running and has IP, it will be used to
  139. // connect to dockerized services (MySQL, etc).
  140. //
  141. // Basically, it adds support for MacOS X and Windows.
  142. func DockerMachineIP() string {
  143.     // Docker-machine is a modern solution for docker in MacOS X.
  144.     // Try to detect it, with fallback to boot2docker
  145.     var dockerMachine bool
  146.     machine := os.Getenv("DOCKER_MACHINE_NAME")
  147.     if machine != "" {
  148.         dockerMachine = true
  149.     }
  150.  
  151.     var buf bytes.Buffer
  152.  
  153.     var cmd *exec.Cmd
  154.     if dockerMachine {
  155.         cmd = exec.Command("docker-machine", "ip", machine)
  156.     } else {
  157.         cmd = exec.Command("boot2docker", "ip")
  158.     }
  159.     cmd.Stdout = &buf
  160.  
  161.     if err := cmd.Run(); err != nil {
  162.         // ignore error, as it's perfectly OK on Linux
  163.         return ""
  164.     }
  165.  
  166.     return buf.String()
  167. }
RAW Paste Data