|
|
@ -6,15 +6,17 @@ import ( |
|
|
|
"encoding/json" |
|
|
|
"encoding/json" |
|
|
|
"flag" |
|
|
|
"flag" |
|
|
|
"fmt" |
|
|
|
"fmt" |
|
|
|
"log" |
|
|
|
|
|
|
|
"os" |
|
|
|
"os" |
|
|
|
"os/exec" |
|
|
|
"os/exec" |
|
|
|
"path/filepath" |
|
|
|
"path/filepath" |
|
|
|
"time" |
|
|
|
"time" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
"github.com/bilibili/kratos/pkg/log" |
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
var ( |
|
|
|
var ( |
|
|
|
retry int |
|
|
|
retry int |
|
|
|
|
|
|
|
noDown bool |
|
|
|
yamlPath string |
|
|
|
yamlPath string |
|
|
|
pathHash string |
|
|
|
pathHash string |
|
|
|
services map[string]*Container |
|
|
|
services map[string]*Container |
|
|
@ -22,85 +24,78 @@ var ( |
|
|
|
|
|
|
|
|
|
|
|
func init() { |
|
|
|
func init() { |
|
|
|
flag.StringVar(&yamlPath, "f", "docker-compose.yaml", "composer yaml path.") |
|
|
|
flag.StringVar(&yamlPath, "f", "docker-compose.yaml", "composer yaml path.") |
|
|
|
|
|
|
|
flag.BoolVar(&noDown, "nodown", false, "containers are not recycled.") |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Setup setup UT related environment dependence for everything.
|
|
|
|
func runCompose(args ...string) (output []byte, err error) { |
|
|
|
func Setup() (err error) { |
|
|
|
|
|
|
|
if _, err = os.Stat(yamlPath); os.IsNotExist(err) { |
|
|
|
if _, err = os.Stat(yamlPath); os.IsNotExist(err) { |
|
|
|
log.Println("composer yaml is not exist!", yamlPath) |
|
|
|
log.Error("os.Stat(%s) composer yaml is not exist!", yamlPath) |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
if yamlPath, err = filepath.Abs(yamlPath); err != nil { |
|
|
|
if yamlPath, err = filepath.Abs(yamlPath); err != nil { |
|
|
|
log.Printf("filepath.Abs(%s) error(%v)", yamlPath, err) |
|
|
|
log.Error("filepath.Abs(%s) error(%v)", yamlPath, err) |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
pathHash = fmt.Sprintf("%x", md5.Sum([]byte(yamlPath)))[:9] |
|
|
|
pathHash = fmt.Sprintf("%x", md5.Sum([]byte(yamlPath)))[:9] |
|
|
|
var args = []string{"-f", yamlPath, "-p", pathHash, "up", "-d"} |
|
|
|
args = append([]string{"-f", yamlPath, "-p", pathHash}, args...) |
|
|
|
if err = exec.Command("docker-compose", args...).Run(); err != nil { |
|
|
|
if output, err = exec.Command("docker-compose", args...).CombinedOutput(); err != nil { |
|
|
|
log.Printf("exec.Command(docker-compose) args(%v) error(%v)", args, err) |
|
|
|
log.Error("exec.Command(docker-compose) args(%v) stdout(%s) error(%v)", args, string(output), err) |
|
|
|
Teardown() |
|
|
|
|
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
// 拿到yaml文件中的服务名,同时通过服务名获取到启动的容器ID
|
|
|
|
|
|
|
|
if _, err = getServices(); err != nil { |
|
|
|
|
|
|
|
Teardown() |
|
|
|
|
|
|
|
return |
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Setup setup UT related environment dependence for everything.
|
|
|
|
|
|
|
|
func Setup() (err error) { |
|
|
|
|
|
|
|
if _, err = runCompose("up", "-d"); err != nil { |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
defer func() { |
|
|
|
|
|
|
|
if err != err { |
|
|
|
|
|
|
|
go Teardown() |
|
|
|
} |
|
|
|
} |
|
|
|
// 通过容器ID检测容器的状态,包括容器服务的状态
|
|
|
|
}() |
|
|
|
if _, err = checkServices(); err != nil { |
|
|
|
if _, err = getServices(); err != nil { |
|
|
|
Teardown() |
|
|
|
|
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
_, err = checkServices() |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Teardown unsetup all environment dependence.
|
|
|
|
// Teardown unsetup all environment dependence.
|
|
|
|
func Teardown() (err error) { |
|
|
|
func Teardown() (err error) { |
|
|
|
if _, err = os.Stat(yamlPath); os.IsNotExist(err) { |
|
|
|
if !noDown { |
|
|
|
log.Println("composer yaml is not exist!") |
|
|
|
_, err = runCompose("down") |
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if yamlPath, err = filepath.Abs(yamlPath); err != nil { |
|
|
|
|
|
|
|
log.Printf("filepath.Abs(%s) error(%v)", yamlPath, err) |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
pathHash = fmt.Sprintf("%x", md5.Sum([]byte(yamlPath)))[:9] |
|
|
|
|
|
|
|
args := []string{"-f", yamlPath, "-p", pathHash, "down"} |
|
|
|
|
|
|
|
if output, err := exec.Command("docker-compose", args...).CombinedOutput(); err != nil { |
|
|
|
|
|
|
|
log.Fatalf("exec.Command(docker-compose) args(%v) stdout(%s) error(%v)", args, string(output), err) |
|
|
|
|
|
|
|
return err |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func getServices() (output []byte, err error) { |
|
|
|
func getServices() (output []byte, err error) { |
|
|
|
var args = []string{"-f", yamlPath, "-p", pathHash, "config", "--services"} |
|
|
|
if output, err = runCompose("config", "--services"); err != nil { |
|
|
|
if output, err = exec.Command("docker-compose", args...).CombinedOutput(); err != nil { |
|
|
|
|
|
|
|
log.Printf("exec.Command(docker-compose) args(%v) stdout(%s) error(%v)", args, string(output), err) |
|
|
|
|
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
services = make(map[string]*Container) |
|
|
|
services = make(map[string]*Container) |
|
|
|
output = bytes.TrimSpace(output) |
|
|
|
output = bytes.TrimSpace(output) |
|
|
|
for _, svr := range bytes.Split(output, []byte("\n")) { |
|
|
|
for _, svr := range bytes.Split(output, []byte("\n")) { |
|
|
|
args = []string{"-f", yamlPath, "-p", pathHash, "ps", "-a", "-q", string(svr)} |
|
|
|
if output, err = runCompose("ps", "-a", "-q", string(svr)); err != nil { |
|
|
|
if output, err = exec.Command("docker-compose", args...).CombinedOutput(); err != nil { |
|
|
|
|
|
|
|
log.Printf("exec.Command(docker-compose) args(%v) stdout(%s) error(%v)", args, string(output), err) |
|
|
|
|
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
var id = string(bytes.TrimSpace(output)) |
|
|
|
var ( |
|
|
|
|
|
|
|
id = string(bytes.TrimSpace(output)) |
|
|
|
args = []string{"inspect", id, "--format", "'{{json .}}'"} |
|
|
|
args = []string{"inspect", id, "--format", "'{{json .}}'"} |
|
|
|
|
|
|
|
) |
|
|
|
if output, err = exec.Command("docker", args...).CombinedOutput(); err != nil { |
|
|
|
if output, err = exec.Command("docker", args...).CombinedOutput(); err != nil { |
|
|
|
log.Printf("exec.Command(docker) args(%v) stdout(%s) error(%v)", args, string(output), err) |
|
|
|
log.Error("exec.Command(docker) args(%v) stdout(%s) error(%v)", args, string(output), err) |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
if output = bytes.TrimSpace(output); bytes.Equal(output, []byte("")) { |
|
|
|
if output = bytes.TrimSpace(output); bytes.Equal(output, []byte("")) { |
|
|
|
err = fmt.Errorf("service: %s | container: %s fails to launch", svr, id) |
|
|
|
err = fmt.Errorf("service: %s | container: %s fails to launch", svr, id) |
|
|
|
log.Printf("exec.Command(docker) args(%v) error(%v)", args, err) |
|
|
|
log.Error("exec.Command(docker) args(%v) error(%v)", args, err) |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
var c = &Container{} |
|
|
|
var c = &Container{} |
|
|
|
if err = json.Unmarshal(bytes.Trim(output, "'"), c); err != nil { |
|
|
|
if err = json.Unmarshal(bytes.Trim(output, "'"), c); err != nil { |
|
|
|
log.Printf("json.Unmarshal(%s) error(%v)", string(output), err) |
|
|
|
log.Error("json.Unmarshal(%s) error(%v)", string(output), err) |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
services[string(svr)] = c |
|
|
|
services[string(svr)] = c |
|
|
@ -121,7 +116,7 @@ func checkServices() (output []byte, err error) { |
|
|
|
}() |
|
|
|
}() |
|
|
|
for svr, c := range services { |
|
|
|
for svr, c := range services { |
|
|
|
if err = c.Healthcheck(); err != nil { |
|
|
|
if err = c.Healthcheck(); err != nil { |
|
|
|
log.Printf("healthcheck(%s) error(%v) retrying %d times...", svr, err, 5-retry) |
|
|
|
log.Error("healthcheck(%s) error(%v) retrying %d times...", svr, err, 5-retry) |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
// TODO About container check and more...
|
|
|
|
// TODO About container check and more...
|
|
|
|