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