SHARE
TWEET

Dockertest package

a guest Nov 19th, 2015 240 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
Top