This is an automated email from the ASF dual-hosted git repository.

wusheng pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/skywalking-infra-e2e.git


The following commit(s) were added to refs/heads/main by this push:
     new c5d37eb  Upgrade docker-compose framework (#22)
c5d37eb is described below

commit c5d37eb3c06aeb9f0ce03638dbfaf5644ac29df8
Author: mrproliu <[email protected]>
AuthorDate: Fri Jun 25 07:09:09 2021 +0800

    Upgrade docker-compose framework (#22)
---
 dist/LICENSE                         |   5 +-
 go.mod                               |   5 +-
 go.sum                               |   8 +-
 internal/components/setup/compose.go | 152 +++++++++++------------------------
 4 files changed, 56 insertions(+), 114 deletions(-)

diff --git a/dist/LICENSE b/dist/LICENSE
index e25fc62..018bc6e 100644
--- a/dist/LICENSE
+++ b/dist/LICENSE
@@ -225,12 +225,13 @@ The text of each license is the standard Apache 2.0 
license.
     cli-runtime v0.19.0: https://github.com/kubernetes/cli-runtime Apache 2.0
     client-go v0.19.0 https://github.com/kubernetes/client-go Apache 2.0
     kubectl v0.19.0: https://github.com/kubernetes/kubectl Apache 2.0
-    docker v20.10.3: https://github.com/docker/docker Apache 2.0
+    docker v20.10.7: https://github.com/docker/docker Apache 2.0
     utils v0.0.0-20201110183641-67b214c5f920: 
https://github.com/kubernetes/utils Apache 2.0
     containerd v1.4.3: https://github.com/containerd/containerd Apache 2.0
     go-connections v0.4.0: https://github.com/docker/go-connections Apache 2.0
     go-units v0.4.0: https://github.com/docker/go-units Apache 2.0
     image-spec v1.0.1: https://github.com/opencontainers/image-spec Apache 2.0
+    go-connections v0.4.0: https://github.com/opencontainers/image-spec Apache 
2.0
 
 ========================================================================
 MIT licenses
@@ -242,7 +243,7 @@ The text of each license is also included at 
licenses/LICENSE-[project].txt.
     logrus 1.7.0: https://github.com/sirupsen/logrus MIT
     go-winio v0.4.16: https://github.com/Microsoft/go-winio MIT
     aec v1.0.0: https://github.com/morikuni/aec MIT
-    testcontainers-go v0.11.0: 
https://github.com/testcontainers/testcontainers-go MIT
+    testcontainers-go v0.11.1: 
https://github.com/testcontainers/testcontainers-go MIT
 
 ========================================================================
 BSD licenses
diff --git a/go.mod b/go.mod
index c1c3c9d..ce51fdd 100644
--- a/go.mod
+++ b/go.mod
@@ -3,13 +3,14 @@ module github.com/apache/skywalking-infra-e2e
 go 1.13
 
 require (
-       github.com/docker/docker v20.10.6+incompatible
+       github.com/docker/docker v20.10.7+incompatible
+       github.com/docker/go-connections v0.4.0
        github.com/google/go-cmp v0.5.4
        github.com/gorilla/mux v1.8.0 // indirect
        github.com/morikuni/aec v1.0.0 // indirect
        github.com/sirupsen/logrus v1.7.0
        github.com/spf13/cobra v1.1.1
-       github.com/testcontainers/testcontainers-go v0.11.0
+       github.com/testcontainers/testcontainers-go v0.11.1
        gopkg.in/yaml.v2 v2.4.0
        k8s.io/api v0.20.7
        k8s.io/apimachinery v0.20.7
diff --git a/go.sum b/go.sum
index ef890e0..6257f86 100644
--- a/go.sum
+++ b/go.sum
@@ -215,8 +215,8 @@ github.com/docker/distribution 
v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TT
 github.com/docker/distribution 
v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod 
h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
 github.com/docker/distribution v2.7.1+incompatible 
h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
 github.com/docker/distribution v2.7.1+incompatible/go.mod 
h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
-github.com/docker/docker v20.10.6+incompatible 
h1:oXI3Vas8TI8Eu/EjH4srKHJBVqraSzJybhxY7Om9faQ=
-github.com/docker/docker v20.10.6+incompatible/go.mod 
h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/docker v20.10.7+incompatible 
h1:Z6O9Nhsjv+ayUEeI1IojKbYcsGdgYSNqxe1s2MYzUhQ=
+github.com/docker/docker v20.10.7+incompatible/go.mod 
h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
 github.com/docker/go-connections v0.4.0 
h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
 github.com/docker/go-connections v0.4.0/go.mod 
h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
 github.com/docker/go-events v0.0.0-20170721190031-9461782956ad/go.mod 
h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
@@ -642,8 +642,8 @@ github.com/syndtr/gocapability 
v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG
 github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod 
h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
 github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod 
h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
 github.com/tchap/go-patricia v2.2.6+incompatible/go.mod 
h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I=
-github.com/testcontainers/testcontainers-go v0.11.0 
h1:HO5YOx2DYBHqcg4MzVWPj3FuHAv7USWVu94vCSsgiaM=
-github.com/testcontainers/testcontainers-go v0.11.0/go.mod 
h1:HztBCODzuA+YpMXGK8amjO8j50jz2gcT0BOzSKUiYIs=
+github.com/testcontainers/testcontainers-go v0.11.1 
h1:FiYsB83LSGbiawoV8TpAZGfcCUbtaeeg1SXqEKUxh08=
+github.com/testcontainers/testcontainers-go v0.11.1/go.mod 
h1:/V0UVq+1e7NWYoqTPog179clf0Qp9TOyp4EcXaEFQz8=
 github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod 
h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
 github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod 
h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
 github.com/ugorji/go v1.1.4/go.mod 
h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
diff --git a/internal/components/setup/compose.go 
b/internal/components/setup/compose.go
index 31b7aa7..07ec57c 100644
--- a/internal/components/setup/compose.go
+++ b/internal/components/setup/compose.go
@@ -21,12 +21,15 @@ package setup
 import (
        "context"
        "fmt"
-       "net"
        "os"
        "regexp"
-       "syscall"
+       "strconv"
+       "strings"
        "time"
 
+       "github.com/docker/go-connections/nat"
+       "github.com/testcontainers/testcontainers-go/wait"
+
        "github.com/apache/skywalking-infra-e2e/internal/config"
        "github.com/apache/skywalking-infra-e2e/internal/constant"
        "github.com/apache/skywalking-infra-e2e/internal/logger"
@@ -57,13 +60,8 @@ func ComposeSetup(e2eConfig *config.E2EConfig) error {
        }
        identifier := GetIdentity()
        compose := testcontainers.NewLocalDockerCompose(composeFilePaths, 
identifier)
-       execError := compose.WithCommand([]string{"up", "-d"}).Invoke()
-       if execError.Error != nil {
-               return execError.Error
-       }
 
-       // record time now
-       timeNow := time.Now()
+       // bind wait port
        timeout := e2eConfig.Setup.Timeout
        var waitTimeout time.Duration
        if timeout <= 0 {
@@ -71,16 +69,37 @@ func ComposeSetup(e2eConfig *config.E2EConfig) error {
        } else {
                waitTimeout = time.Duration(timeout) * time.Second
        }
-       logger.Log.Debugf("wait timeout is %d seconds", 
int(waitTimeout.Seconds()))
-
-       // find exported port and build env
+       serviceWithPorts := make(map[string][]int)
        for service, content := range compose.Services {
                serviceConfig := content.(map[interface{}]interface{})
                ports := serviceConfig["ports"]
                if ports == nil {
                        continue
                }
+               serviceWithPorts[service] = []int{}
+
                portList := ports.([]interface{})
+               for inx := range portList {
+                       exportPort, err := getExpectPort(portList[inx])
+                       if err != nil {
+                               return err
+                       }
+                       serviceWithPorts[service] = 
append(serviceWithPorts[service], exportPort)
+
+                       compose.WithExposedService(
+                               service,
+                               exportPort,
+                               
wait.NewHostPortStrategy(nat.Port(fmt.Sprintf("%d/tcp", 
exportPort))).WithStartupTimeout(waitTimeout))
+               }
+       }
+
+       execError := compose.WithCommand([]string{"up", "-d"}).Invoke()
+       if execError.Error != nil {
+               return execError.Error
+       }
+
+       // find exported port and build env
+       for service, portList := range serviceWithPorts {
                container, err := findContainer(cli, fmt.Sprintf("%s_%s", 
identifier, getInstanceName(service)))
                if err != nil {
                        return err
@@ -89,20 +108,10 @@ func ComposeSetup(e2eConfig *config.E2EConfig) error {
 
                for inx := range portList {
                        for _, containerPort := range containerPorts {
-                               if int(containerPort.PrivatePort) != 
portList[inx].(int) {
+                               if int(containerPort.PrivatePort) != 
portList[inx] {
                                        continue
                                }
 
-                               // calculate max wait time
-                               waitTimeout = NewTimeout(timeNow, waitTimeout)
-                               timeNow = time.Now()
-
-                               // wait port and export
-                               err := waitTCPPortStarted(context.Background(), 
cli, container, int(containerPort.PublicPort), int(containerPort.PrivatePort), 
waitTimeout)
-                               if err != nil {
-                                       return fmt.Errorf("could wait port 
exported: %s:%d, %v", service, portList[inx], err)
-                               }
-
                                // expose env config to env
                                // format: <service_name>_<port>
                                envKey := fmt.Sprintf("%s_%d", service, 
containerPort.PrivatePort)
@@ -112,6 +121,7 @@ func ComposeSetup(e2eConfig *config.E2EConfig) error {
                                        return fmt.Errorf("could not set env 
for %s:%d, %v", service, portList[inx], err)
                                }
                                logger.Log.Infof("expose env : %s : %s", 
envKey, envValue)
+                               break
                        }
                }
        }
@@ -119,6 +129,20 @@ func ComposeSetup(e2eConfig *config.E2EConfig) error {
        return nil
 }
 
+func getExpectPort(portConfig interface{}) (int, error) {
+       switch conf := portConfig.(type) {
+       case int:
+               return conf, nil
+       case string:
+               portInfo := strings.Split(conf, ":")
+               if len(portInfo) > 1 {
+                       return strconv.Atoi(portInfo[1])
+               }
+               return strconv.Atoi(portInfo[0])
+       }
+       return 0, fmt.Errorf("unknown port information: %v", portConfig)
+}
+
 func findContainer(c *client.Client, instanceName string) (*types.Container, 
error) {
        f := filters.NewArgs(filters.Arg("name", instanceName))
        containerListOptions := types.ContainerListOptions{Filters: f}
@@ -133,90 +157,6 @@ func findContainer(c *client.Client, instanceName string) 
(*types.Container, err
        return &containers[0], nil
 }
 
-func waitTCPPortStarted(ctx context.Context, c *client.Client, container 
*types.Container, publicPort, interPort int, timeout time.Duration) error {
-       // limit context to startupTimeout
-       ctx, cancelContext := context.WithTimeout(ctx, timeout)
-       defer cancelContext()
-
-       var waitInterval = 100 * time.Millisecond
-
-       // external check
-       dialer := net.Dialer{}
-       address := net.JoinHostPort("127.0.0.1", fmt.Sprintf("%d", publicPort))
-       for {
-               conn, err := dialer.DialContext(ctx, "tcp", address)
-               if err != nil {
-                       if v, ok := err.(*net.OpError); ok {
-                               if v2, ok := (v.Err).(*os.SyscallError); ok {
-                                       if isConnRefusedErr(v2.Err) {
-                                               time.Sleep(waitInterval)
-                                               continue
-                                       }
-                               }
-                       }
-                       return err
-               }
-               conn.Close()
-               break
-       }
-
-       // internal check
-       command := buildInternalCheckCommand(interPort)
-       for {
-               if ctx.Err() != nil {
-                       return ctx.Err()
-               }
-               response, err := c.ContainerExecCreate(ctx, container.ID, 
types.ExecConfig{
-                       Cmd:          []string{"/bin/sh", "-c", command},
-                       AttachStderr: true,
-                       AttachStdout: true,
-               })
-               if err != nil {
-                       return err
-               }
-
-               err = c.ContainerExecStart(ctx, response.ID, 
types.ExecStartCheck{
-                       Detach: false,
-               })
-               if err != nil {
-                       return err
-               }
-
-               var exitCode int
-               for {
-                       execResp, err := c.ContainerExecInspect(ctx, 
response.ID)
-                       if err != nil {
-                               return err
-                       }
-
-                       if !execResp.Running {
-                               exitCode = execResp.ExitCode
-                               break
-                       }
-
-                       time.Sleep(waitInterval)
-               }
-
-               if exitCode == 0 {
-                       return nil
-               }
-       }
-}
-
-func buildInternalCheckCommand(internalPort int) string {
-       command := `(
-                                       nc -vz -w 1 localhost %d || 
-                                       cat /proc/net/tcp | awk '{print $2}' | 
grep -i :%d || 
-                                       </dev/tcp/localhost/%d
-                               )
-                               `
-       return "true && " + fmt.Sprintf(command, internalPort, internalPort, 
internalPort)
-}
-
-func isConnRefusedErr(err error) bool {
-       return err == syscall.ECONNREFUSED
-}
-
 func getInstanceName(serviceName string) string {
        match, err := regexp.MatchString(".*_[0-9]+", serviceName)
        if err != nil {

Reply via email to