Last active
September 19, 2016 09:32
-
-
Save gingerhot/82d31952375529dd8e8e59b81adf5797 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package dockertest | |
import ( | |
"bytes" | |
"fmt" | |
"log" | |
"net" | |
"os" | |
"os/exec" | |
"strings" | |
"time" | |
"github.com/fsouza/go-dockerclient" | |
) | |
// StartMysql starts new docker container with MySQL running. | |
// | |
// It returns dsn, defer function and error if any. | |
func StartMysql() (string, func(), error) { | |
client, err := docker.NewClientFromEnv() | |
if err != nil { | |
return "", nil, err | |
} | |
c, err := client.CreateContainer(CreateOptions()) | |
if err != nil { | |
return "", nil, err | |
} | |
deferFn := func() { | |
if err := client.RemoveContainer(docker.RemoveContainerOptions{ | |
ID: c.ID, | |
Force: true, | |
}); err != nil { | |
log.Println("cannot remove container: %v", err) | |
} | |
} | |
// VM IP is the IP of DockerMachine VM, if running (used in non-Linux OSes) | |
vm_ip := strings.TrimSpace(DockerMachineIP()) | |
var nonLinux bool = (vm_ip != "") | |
err = client.StartContainer(c.ID, StartOptions(nonLinux)) | |
if err != nil { | |
deferFn() | |
return "", nil, err | |
} | |
// wait for container to wake up | |
if err := waitStarted(client, c.ID, 5*time.Second); err != nil { | |
deferFn() | |
return "", nil, err | |
} | |
if c, err = client.InspectContainer(c.ID); err != nil { | |
deferFn() | |
return "", nil, err | |
} | |
// determine IP address for MySQL | |
ip := "" | |
if vm_ip != "" { | |
ip = vm_ip | |
} else if c.NetworkSettings != nil { | |
ip = strings.TrimSpace(c.NetworkSettings.IPAddress) | |
} | |
// wait MySQL to wake up | |
if err := waitReachable(ip+":3306", 5*time.Second); err != nil { | |
deferFn() | |
return "", nil, err | |
} | |
return dsn(ip), deferFn, nil | |
} | |
// dsn returns valid dsn to be used with mysql driver for the given ip. | |
func dsn(ip string) string { | |
return fmt.Sprintf("root:@tcp(%s:3306)/mydb", ip) | |
} | |
func CreateOptions() docker.CreateContainerOptions { | |
ports := make(map[docker.Port]struct{}) | |
ports["3306"] = struct{}{} | |
opts := docker.CreateContainerOptions{ | |
Config: &docker.Config{ | |
Image: "mydb_test", | |
ExposedPorts: ports, | |
}, | |
} | |
return opts | |
} | |
func StartOptions(bindPorts bool) *docker.HostConfig { | |
port_binds := make(map[docker.Port][]docker.PortBinding) | |
if bindPorts { | |
port_binds["3306"] = []docker.PortBinding{ | |
docker.PortBinding{HostPort: "3306"}, | |
} | |
} | |
conf := docker.HostConfig{ | |
PortBindings: port_binds, | |
} | |
return &conf | |
} | |
// waitReachable waits for hostport to became reachable for the maxWait time. | |
func waitReachable(hostport string, maxWait time.Duration) error { | |
done := time.Now().Add(maxWait) | |
for time.Now().Before(done) { | |
c, err := net.Dial("tcp", hostport) | |
if err == nil { | |
c.Close() | |
return nil | |
} | |
time.Sleep(100 * time.Millisecond) | |
} | |
return fmt.Errorf("cannot connect %v for %v", hostport, maxWait) | |
} | |
// waitStarted waits for container to start for the maxWait time. | |
func waitStarted(client *docker.Client, id string, maxWait time.Duration) error { | |
done := time.Now().Add(maxWait) | |
for time.Now().Before(done) { | |
c, err := client.InspectContainer(id) | |
if err != nil { | |
break | |
} | |
if c.State.Running { | |
return nil | |
} | |
time.Sleep(100 * time.Millisecond) | |
} | |
return fmt.Errorf("cannot start container %s for %v", id, maxWait) | |
} | |
// DockerMachineIP returns IP of docker-machine or boot2docker VM instance. | |
// | |
// If docker-machine or boot2docker is running and has IP, it will be used to | |
// connect to dockerized services (MySQL, etc). | |
// | |
// Basically, it adds support for MacOS X and Windows. | |
func DockerMachineIP() string { | |
// Docker-machine is a modern solution for docker in MacOS X. | |
// Try to detect it, with fallback to boot2docker | |
var dockerMachine bool | |
machine := os.Getenv("DOCKER_MACHINE_NAME") | |
if machine != "" { | |
dockerMachine = true | |
} | |
var buf bytes.Buffer | |
var cmd *exec.Cmd | |
if dockerMachine { | |
cmd = exec.Command("docker-machine", "ip", machine) | |
} else { | |
cmd = exec.Command("boot2docker", "ip") | |
} | |
cmd.Stdout = &buf | |
if err := cmd.Run(); err != nil { | |
// ignore error, as it's perfectly OK on Linux | |
return "" | |
} | |
return buf.String() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment