|
1 | 1 | package main |
2 | 2 |
|
3 | 3 | import ( |
| 4 | + "bytes" |
| 5 | + "errors" |
4 | 6 | "fmt" |
| 7 | + "io/ioutil" |
| 8 | + "net/http" |
| 9 | + "os" |
5 | 10 | "os/exec" |
| 11 | + "strconv" |
| 12 | + "strings" |
| 13 | + "time" |
| 14 | + |
| 15 | + "github.com/msaf1980/go-stringutils" |
6 | 16 | ) |
7 | 17 |
|
8 | 18 | var ClickhouseContainerName = "clickhouse-server-gch-test" |
| 19 | +var ClickhouseOldImage = "yandex/clickhouse-server" |
| 20 | +var ClickhouseDefaultImage = "clickhouse/clickhouse-server" |
9 | 21 |
|
10 | 22 | type Clickhouse struct { |
11 | 23 | Version string `toml:"version"` |
12 | 24 | Dir string `toml:"dir"` |
13 | 25 |
|
14 | | - Docker string `toml:"docker"` |
15 | 26 | DockerImage string `toml:"image"` |
16 | 27 |
|
17 | | - address string `toml:"-"` |
18 | | - container string `toml:"-"` |
| 28 | + TZ string `toml:"tz"` // override timezone |
| 29 | + |
| 30 | + httpAddress string `toml:"-"` |
| 31 | + url string `toml:"-"` |
| 32 | + container string `toml:"-"` |
19 | 33 | } |
20 | 34 |
|
21 | | -func (c *Clickhouse) Start() (error, string) { |
22 | | - if len(c.Version) == 0 { |
23 | | - return fmt.Errorf("version not set"), "" |
| 35 | +func (c *Clickhouse) CheckConfig(rootDir string) error { |
| 36 | + if c.Version == "" { |
| 37 | + c.Version = "latest" |
24 | 38 | } |
25 | 39 | if len(c.Dir) == 0 { |
26 | | - return fmt.Errorf("dir not set"), "" |
| 40 | + return ErrNoSetDir |
27 | 41 | } |
28 | | - if len(c.Docker) == 0 { |
29 | | - c.Docker = "docker" |
| 42 | + if !strings.HasPrefix(c.Dir, "/") { |
| 43 | + c.Dir = rootDir + "/" + c.Dir |
30 | 44 | } |
31 | | - if len(c.DockerImage) == 0 { |
32 | | - c.DockerImage = "yandex/clickhouse-server" |
| 45 | + |
| 46 | + if c.DockerImage == "" { |
| 47 | + if c.Version == "latest" { |
| 48 | + c.DockerImage = ClickhouseDefaultImage |
| 49 | + } else { |
| 50 | + splitV := strings.Split(c.Version, ".") |
| 51 | + majorV, err := strconv.Atoi(splitV[0]) |
| 52 | + if err != nil { |
| 53 | + c.DockerImage = ClickhouseDefaultImage |
| 54 | + } else if majorV >= 21 { |
| 55 | + c.DockerImage = ClickhouseDefaultImage |
| 56 | + } else { |
| 57 | + c.DockerImage = ClickhouseOldImage |
| 58 | + } |
| 59 | + } |
33 | 60 | } |
| 61 | + return nil |
| 62 | +} |
| 63 | + |
| 64 | +func (c *Clickhouse) Key() string { |
| 65 | + return c.DockerImage + ":" + c.Version + " " + c.Dir + " TZ " + c.TZ |
| 66 | +} |
| 67 | + |
| 68 | +func (c *Clickhouse) Start() (string, error) { |
34 | 69 | var err error |
35 | | - c.address, err = getFreeTCPPort("") |
| 70 | + c.httpAddress, err = getFreeTCPPort("") |
36 | 71 | if err != nil { |
37 | | - return err, "" |
| 72 | + return "", err |
38 | 73 | } |
| 74 | + c.url = "http://" + c.httpAddress |
39 | 75 |
|
40 | 76 | c.container = ClickhouseContainerName |
41 | 77 |
|
| 78 | + // tz, _ := localTZLocationName() |
| 79 | + |
42 | 80 | chStart := []string{"run", "-d", |
43 | 81 | "--name", c.container, |
44 | 82 | "--ulimit", "nofile=262144:262144", |
45 | | - "-p", c.address + ":8123", |
46 | | - //"-e", "TZ=UTC", |
| 83 | + "-p", c.httpAddress + ":8123", |
| 84 | + // "-e", "TZ=" + tz, // workaround for TZ=":/etc/localtime" |
47 | 85 | "-v", c.Dir + "/config.xml:/etc/clickhouse-server/config.xml", |
48 | 86 | "-v", c.Dir + "/users.xml:/etc/clickhouse-server/users.xml", |
49 | 87 | "-v", c.Dir + "/rollup.xml:/etc/clickhouse-server/config.d/rollup.xml", |
50 | 88 | "-v", c.Dir + "/init.sql:/docker-entrypoint-initdb.d/init.sql", |
51 | | - c.DockerImage + ":" + c.Version, |
| 89 | + } |
| 90 | + if c.TZ != "" { |
| 91 | + chStart = append(chStart, "-e", "TZ="+c.TZ) |
52 | 92 | } |
53 | 93 |
|
54 | | - cmd := exec.Command(c.Docker, chStart...) |
| 94 | + chStart = append(chStart, c.DockerImage+":"+c.Version) |
| 95 | + |
| 96 | + cmd := exec.Command(DockerBinary, chStart...) |
55 | 97 | out, err := cmd.CombinedOutput() |
56 | 98 |
|
57 | | - return err, string(out) |
| 99 | + return string(out), err |
58 | 100 | } |
59 | 101 |
|
60 | | -func (c *Clickhouse) Stop(delete bool) (error, string) { |
| 102 | +func (c *Clickhouse) Stop(delete bool) (string, error) { |
61 | 103 | if len(c.container) == 0 { |
62 | | - return nil, "" |
| 104 | + return "", nil |
63 | 105 | } |
64 | 106 |
|
65 | 107 | chStop := []string{"stop", c.container} |
66 | 108 |
|
67 | | - cmd := exec.Command(c.Docker, chStop...) |
| 109 | + cmd := exec.Command(DockerBinary, chStop...) |
68 | 110 | out, err := cmd.CombinedOutput() |
69 | 111 |
|
70 | 112 | if err == nil && delete { |
71 | 113 | return c.Delete() |
72 | 114 | } |
73 | | - return err, string(out) |
| 115 | + return string(out), err |
74 | 116 | } |
75 | 117 |
|
76 | | -func (c *Clickhouse) Delete() (error, string) { |
| 118 | +func (c *Clickhouse) Delete() (string, error) { |
77 | 119 | if len(c.container) == 0 { |
78 | | - return nil, "" |
| 120 | + return "", nil |
79 | 121 | } |
80 | 122 |
|
81 | 123 | chDel := []string{"rm", c.container} |
82 | 124 |
|
83 | | - cmd := exec.Command(c.Docker, chDel...) |
| 125 | + cmd := exec.Command(DockerBinary, chDel...) |
84 | 126 | out, err := cmd.CombinedOutput() |
85 | 127 |
|
86 | 128 | if err == nil { |
87 | 129 | c.container = "" |
88 | 130 | } |
89 | 131 |
|
90 | | - return err, string(out) |
| 132 | + return string(out), err |
91 | 133 | } |
92 | 134 |
|
93 | | -func (c *Clickhouse) Address() string { |
94 | | - return c.address |
| 135 | +func (c *Clickhouse) URL() string { |
| 136 | + return c.url |
95 | 137 | } |
96 | 138 |
|
97 | 139 | func (c *Clickhouse) Container() string { |
98 | 140 | return c.container |
99 | 141 | } |
| 142 | + |
| 143 | +func (c *Clickhouse) Exec(sql string) (bool, string) { |
| 144 | + return containerExec(c.container, []string{"sh", "-c", "clickhouse-client -q '" + sql + "'"}) |
| 145 | +} |
| 146 | + |
| 147 | +func (c *Clickhouse) Query(sql string) (string, error) { |
| 148 | + reader := strings.NewReader(sql) |
| 149 | + request, err := http.NewRequest("POST", c.URL(), reader) |
| 150 | + if err != nil { |
| 151 | + return "", err |
| 152 | + } |
| 153 | + |
| 154 | + httpClient := http.Client{ |
| 155 | + Timeout: time.Minute, |
| 156 | + } |
| 157 | + resp, err := httpClient.Do(request) |
| 158 | + if err != nil { |
| 159 | + return "", err |
| 160 | + } |
| 161 | + msg, err := ioutil.ReadAll(resp.Body) |
| 162 | + if err != nil { |
| 163 | + return "", err |
| 164 | + } |
| 165 | + if resp.StatusCode != http.StatusOK { |
| 166 | + return "", errors.New(resp.Status + ": " + string(bytes.TrimRight(msg, "\n"))) |
| 167 | + } |
| 168 | + return string(msg), nil |
| 169 | +} |
| 170 | + |
| 171 | +func (c *Clickhouse) Alive() bool { |
| 172 | + if len(c.container) == 0 { |
| 173 | + return false |
| 174 | + } |
| 175 | + req, err := http.DefaultClient.Get(c.url) |
| 176 | + if err != nil { |
| 177 | + return false |
| 178 | + } |
| 179 | + return req.StatusCode == http.StatusOK |
| 180 | +} |
| 181 | + |
| 182 | +func (c *Clickhouse) CopyLog(destDir string, tail uint64) error { |
| 183 | + if len(c.container) == 0 { |
| 184 | + return nil |
| 185 | + } |
| 186 | + dest := destDir + "/clickhouse-server.log" |
| 187 | + |
| 188 | + chArgs := []string{"cp", c.container + ":/var/log/clickhouse-server/clickhouse-server.log", dest} |
| 189 | + |
| 190 | + cmd := exec.Command(DockerBinary, chArgs...) |
| 191 | + out, err := cmd.CombinedOutput() |
| 192 | + if err != nil { |
| 193 | + return errors.New(err.Error() + ": " + string(bytes.TrimRight(out, "\n"))) |
| 194 | + } |
| 195 | + |
| 196 | + if tail > 0 { |
| 197 | + out, _ := exec.Command("tail", "-"+strconv.FormatUint(tail, 10), dest).Output() |
| 198 | + fmt.Fprintf(os.Stderr, "CLICKHOUSE-SERVER.LOG %s", stringutils.UnsafeString(out)) |
| 199 | + } |
| 200 | + |
| 201 | + return nil |
| 202 | +} |
| 203 | + |
| 204 | +func (c *Clickhouse) CopyErrLog(destDir string, tail uint64) error { |
| 205 | + if len(c.container) == 0 { |
| 206 | + return nil |
| 207 | + } |
| 208 | + dest := destDir + "/clickhouse-server.err.log" |
| 209 | + |
| 210 | + chArgs := []string{"cp", c.container + ":/var/log/clickhouse-server/clickhouse-server.err.log", dest} |
| 211 | + |
| 212 | + cmd := exec.Command(DockerBinary, chArgs...) |
| 213 | + out, err := cmd.CombinedOutput() |
| 214 | + if err != nil { |
| 215 | + return errors.New(err.Error() + ": " + string(bytes.TrimRight(out, "\n"))) |
| 216 | + } |
| 217 | + |
| 218 | + if tail > 0 { |
| 219 | + out, _ := exec.Command("tail", "-"+strconv.FormatUint(tail, 10), dest).Output() |
| 220 | + fmt.Fprintf(os.Stderr, "CLICKHOUSE-SERVER.ERR %s", stringutils.UnsafeString(out)) |
| 221 | + } |
| 222 | + |
| 223 | + return nil |
| 224 | +} |
0 commit comments