github.com/coincircle/mattermost-server@v4.8.1-0.20180321182714-9d701c704416+incompatible/store/storetest/docker.go (about)

     1  // Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
     2  // See License.txt for license information.
     3  
     4  package storetest
     5  
     6  import (
     7  	"encoding/json"
     8  	"fmt"
     9  	"io"
    10  	"net"
    11  	"os/exec"
    12  	"strings"
    13  	"time"
    14  
    15  	l4g "github.com/alecthomas/log4go"
    16  
    17  	"github.com/mattermost/mattermost-server/model"
    18  )
    19  
    20  type Container struct {
    21  	Id              string
    22  	NetworkSettings struct {
    23  		Ports map[string][]struct {
    24  			HostPort string
    25  		}
    26  	}
    27  }
    28  
    29  type RunningContainer struct {
    30  	Container
    31  }
    32  
    33  func (c *RunningContainer) Stop() error {
    34  	l4g.Info("Removing container: %v", c.Id)
    35  	return exec.Command("docker", "rm", "-f", c.Id).Run()
    36  }
    37  
    38  func NewMySQLContainer() (*RunningContainer, *model.SqlSettings, error) {
    39  	container, err := runContainer([]string{
    40  		"-e", "MYSQL_ROOT_PASSWORD=mostest",
    41  		"-e", "MYSQL_USER=mmuser",
    42  		"-e", "MYSQL_PASSWORD=mostest",
    43  		"-e", "MYSQL_DATABASE=mattermost_test",
    44  		"--tmpfs", "/var/lib/mysql",
    45  		"mysql:5.7",
    46  	})
    47  	if err != nil {
    48  		return nil, nil, err
    49  	}
    50  	l4g.Info("Waiting for mysql connectivity")
    51  	port := container.NetworkSettings.Ports["3306/tcp"][0].HostPort
    52  	if err := waitForPort(port); err != nil {
    53  		container.Stop()
    54  		return nil, nil, err
    55  	}
    56  	return container, databaseSettings("mysql", "mmuser:mostest@tcp(127.0.0.1:"+port+")/mattermost_test?charset=utf8mb4,utf8"), nil
    57  }
    58  
    59  func NewPostgreSQLContainer() (*RunningContainer, *model.SqlSettings, error) {
    60  	container, err := runContainer([]string{
    61  		"-e", "POSTGRES_USER=mmuser",
    62  		"-e", "POSTGRES_PASSWORD=mostest",
    63  		"--tmpfs", "/var/lib/postgresql/data",
    64  		"postgres:9.4",
    65  	})
    66  	if err != nil {
    67  		return nil, nil, err
    68  	}
    69  	l4g.Info("Waiting for postgres connectivity")
    70  	port := container.NetworkSettings.Ports["5432/tcp"][0].HostPort
    71  	if err := waitForPort(port); err != nil {
    72  		container.Stop()
    73  		return nil, nil, err
    74  	}
    75  	return container, databaseSettings("postgres", "postgres://mmuser:mostest@127.0.0.1:"+port+"?sslmode=disable"), nil
    76  }
    77  
    78  func databaseSettings(driver, dataSource string) *model.SqlSettings {
    79  	settings := &model.SqlSettings{
    80  		DriverName:               &driver,
    81  		DataSource:               &dataSource,
    82  		DataSourceReplicas:       []string{},
    83  		DataSourceSearchReplicas: []string{},
    84  		MaxIdleConns:             new(int),
    85  		MaxOpenConns:             new(int),
    86  		Trace:                    false,
    87  		AtRestEncryptKey:         model.NewRandomString(32),
    88  		QueryTimeout:             new(int),
    89  	}
    90  	*settings.MaxIdleConns = 10
    91  	*settings.MaxOpenConns = 100
    92  	*settings.QueryTimeout = 10
    93  	return settings
    94  }
    95  
    96  func runContainer(args []string) (*RunningContainer, error) {
    97  	name := "mattermost-storetest-" + model.NewId()
    98  	dockerArgs := append([]string{"run", "-d", "-P", "--name", name}, args...)
    99  	out, err := exec.Command("docker", dockerArgs...).Output()
   100  	if err != nil {
   101  		return nil, err
   102  	}
   103  	id := strings.TrimSpace(string(out))
   104  	out, err = exec.Command("docker", "inspect", id).Output()
   105  	if err != nil {
   106  		exec.Command("docker", "rm", "-f", id).Run()
   107  		return nil, err
   108  	}
   109  	var containers []Container
   110  	if err := json.Unmarshal(out, &containers); err != nil {
   111  		exec.Command("docker", "rm", "-f", id).Run()
   112  		return nil, err
   113  	}
   114  	l4g.Info("Running container: %v", id)
   115  	return &RunningContainer{containers[0]}, nil
   116  }
   117  
   118  func waitForPort(port string) error {
   119  	deadline := time.Now().Add(time.Minute * 10)
   120  	for time.Now().Before(deadline) {
   121  		conn, err := net.DialTimeout("tcp", "127.0.0.1:"+port, time.Minute)
   122  		if err != nil {
   123  			return err
   124  		}
   125  		if err = conn.SetReadDeadline(time.Now().Add(time.Millisecond * 500)); err != nil {
   126  			return err
   127  		}
   128  		_, err = conn.Read(make([]byte, 1))
   129  		conn.Close()
   130  		if err == nil {
   131  			return nil
   132  		}
   133  		if e, ok := err.(net.Error); ok && e.Timeout() {
   134  			return nil
   135  		}
   136  		if err != io.EOF {
   137  			return err
   138  		}
   139  		time.Sleep(time.Millisecond * 200)
   140  	}
   141  	return fmt.Errorf("timeout waiting for port %v", port)
   142  }