Compare commits

..

10 Commits

Author SHA1 Message Date
Minghe
6214581ca8 Expose logs when container started but exited with errors (#527)
* expose the error message of start failure
* disable container auto-remove, only remove it when it fails to start
* call /containers/id/logs endpoint to get the logs
2020-05-16 18:11:02 +08:00
Minghe Huang
63bc06a993 add task name
replace spinner
2020-05-07 20:01:28 +08:00
Minghe Huang
833b7d06a3 bump version 2020-05-07 18:23:02 +08:00
dependabot-preview[bot]
1ae68f1076 Bump github.com/briandowns/spinner from 1.10.0 to 1.11.1 (#521)
Bumps [github.com/briandowns/spinner](https://github.com/briandowns/spinner) from 1.10.0 to 1.11.1.
- [Release notes](https://github.com/briandowns/spinner/releases)
- [Commits](https://github.com/briandowns/spinner/compare/v1.10.0...v1.11.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
Co-authored-by: Minghe <h.minghe@gmail.com>
2020-05-07 16:53:04 +08:00
Minghe
5ce61ef200 Fix the wrong arch of target host (#524)
* Fix the wrong arch of target host,
* get the OS arch with `uname -a`
* refactor the SSHConnectionTimeout constant
* only provision on remote host
2020-05-07 16:52:45 +08:00
dependabot-preview[bot]
3923c3451f Bump github.com/gin-gonic/gin from 1.6.2 to 1.6.3 (#522)
Bumps [github.com/gin-gonic/gin](https://github.com/gin-gonic/gin) from 1.6.2 to 1.6.3.
- [Release notes](https://github.com/gin-gonic/gin/releases)
- [Changelog](https://github.com/gin-gonic/gin/blob/master/CHANGELOG.md)
- [Commits](https://github.com/gin-gonic/gin/compare/v1.6.2...v1.6.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-05-05 10:02:49 +08:00
Massimiliano Mirra
8741db25b6 use lighter-weight node image (#518) 2020-04-28 10:55:13 +08:00
Minghe
16d20b23a7 fix gosec issue (#519) 2020-04-28 10:43:04 +08:00
dependabot-preview[bot]
5028ba7694 Bump github.com/urfave/cli from 1.22.3 to 1.22.4 (#504)
Bumps [github.com/urfave/cli](https://github.com/urfave/cli) from 1.22.3 to 1.22.4.
- [Release notes](https://github.com/urfave/cli/releases)
- [Changelog](https://github.com/urfave/cli/blob/master/docs/CHANGELOG.md)
- [Commits](https://github.com/urfave/cli/compare/v1.22.3...v1.22.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
Co-authored-by: Minghe <h.minghe@gmail.com>
2020-04-23 12:10:59 +08:00
dependabot-preview[bot]
a324fab432 Bump github.com/apex/log from 1.1.2 to 1.1.4 (#516)
Bumps [github.com/apex/log](https://github.com/apex/log) from 1.1.2 to 1.1.4.
- [Release notes](https://github.com/apex/log/releases)
- [Changelog](https://github.com/apex/log/blob/master/History.md)
- [Commits](https://github.com/apex/log/compare/v1.1.2...v1.1.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-04-23 11:55:45 +08:00
22 changed files with 214 additions and 143 deletions

View File

@@ -1,4 +1,4 @@
FROM node:latest
FROM node:alpine
COPY . .
RUN npm install

View File

@@ -46,7 +46,7 @@ func Restore(box *packr.Box, output string) error {
return err
}
if err := ioutil.WriteFile(dest, content, 0644); err != nil {
if err := ioutil.WriteFile(dest, content, 0600); err != nil {
return err
}

View File

@@ -1,14 +0,0 @@
package config
import (
"os"
)
// DisableContainerAutoremove to tell if to run container with --rm
var DisableContainerAutoremove = false
func init() {
if os.Getenv("DISABLE_CONTAINER_AUTOREMOVE") == "true" {
DisableContainerAutoremove = true
}
}

View File

@@ -1,17 +0,0 @@
package config
import (
"os"
"testing"
)
var _ = func() (_ struct{}) {
os.Setenv("DISABLE_CONTAINER_AUTOREMOVE", "true")
return
}()
func TestEnvLoad(t *testing.T) {
if !DisableContainerAutoremove {
t.Fatalf("should be true after set")
}
}

View File

@@ -22,7 +22,6 @@ import (
"github.com/docker/go-connections/nat"
"github.com/google/go-querystring/query"
"github.com/google/uuid"
fxConfig "github.com/metrue/fx/config"
containerruntimes "github.com/metrue/fx/container_runtimes"
"github.com/metrue/fx/types"
"github.com/metrue/fx/utils"
@@ -425,7 +424,7 @@ func (api *API) StartContainer(ctx context.Context, name string, image string, b
}
hostConfig := &container.HostConfig{
AutoRemove: !fxConfig.DisableContainerAutoremove,
AutoRemove: false,
PortBindings: portMap,
}
@@ -475,11 +474,82 @@ func (api *API) StartContainer(ctx context.Context, name string, image string, b
return errors.New(msg)
}
if _, err = api.inspect(createRes.ID); err != nil {
msg := fmt.Sprintf("inspect container %s error", name)
return errors.Wrap(err, msg)
// wait seconds for container starting
time.Sleep(3 * time.Second)
info, err := api.inspect(createRes.ID)
if err != nil {
return errors.Wrap(err, "failed to inspect container "+createRes.ID)
}
if !info.State.Running {
logs, err := api.logs(createRes.ID)
if err != nil {
return errors.Wrap(err, "could not get logs of container "+createRes.ID)
}
if err := api.RemoveContainer(createRes.ID); err != nil {
msg := fmt.Sprintf("remove container %s failed, and container started with logs: %s", createRes.ID, string(logs))
return errors.Wrap(err, msg)
}
return fmt.Errorf("container start failure: %s", logs)
}
return nil
}
func (api *API) logs(id string) ([]byte, error) {
query := url.Values{}
query.Set("stdout", "true")
query.Set("stderr", "true")
path := fmt.Sprintf("/containers/%s/logs?%s", id, query.Encode())
url := fmt.Sprintf("%s%s", api.endpoint, path)
request, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil, err
}
client := &http.Client{Timeout: 20 * time.Second}
resp, err := client.Do(request)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode == 200 {
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return b, nil
}
return nil, fmt.Errorf("get logs of container %s failed: %d", id, resp.StatusCode)
}
// RemoveContainer remove a container
func (api *API) RemoveContainer(id string) error {
query := url.Values{}
query.Set("v", "true")
path := fmt.Sprintf("/containers/%s?%s", id, query.Encode())
url := fmt.Sprintf("%s%s", api.endpoint, path)
request, err := http.NewRequest("DELETE", url, nil)
if err != nil {
return err
}
client := &http.Client{Timeout: 20 * time.Second}
resp, err := client.Do(request)
if err != nil {
return err
}
defer resp.Body.Close()
output, err := ioutil.ReadAll(resp.Body)
if err != nil {
return errors.Wrap(err, "read response body of remove container request failed")
}
if resp.StatusCode != 204 {
return fmt.Errorf("could not remove container %s: %s", id, string(output))
}
return nil
}

View File

@@ -1,4 +1,4 @@
FROM node:latest
FROM node:alpine
COPY . .
RUN npm install

View File

@@ -18,7 +18,6 @@ import (
"github.com/docker/docker/client"
"github.com/docker/go-connections/nat"
"github.com/google/uuid"
fxConfig "github.com/metrue/fx/config"
containerruntimes "github.com/metrue/fx/container_runtimes"
"github.com/metrue/fx/types"
"github.com/metrue/fx/utils"
@@ -162,7 +161,7 @@ func (d *Docker) StartContainer(ctx context.Context, name string, image string,
}
hostConfig := &dockerTypesContainer.HostConfig{
AutoRemove: !fxConfig.DisableContainerAutoremove,
AutoRemove: false,
PortBindings: portMap,
}
resp, err := d.ContainerCreate(ctx, config, hostConfig, nil, name)

2
fx.go
View File

@@ -19,7 +19,7 @@ import (
_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
)
const version = "0.9.35"
const version = "0.9.41"
func init() {
go checkForUpdate()

9
go.mod
View File

@@ -5,14 +5,15 @@ go 1.12
require (
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect
github.com/Microsoft/go-winio v0.4.14 // indirect
github.com/apex/log v1.1.2
github.com/briandowns/spinner v1.10.0
github.com/apex/log v1.1.4
github.com/briandowns/spinner v1.11.1
github.com/cheggaaa/pb/v3 v3.0.4
github.com/docker/distribution v2.7.1+incompatible // indirect
github.com/docker/docker v0.0.0-20190313072916-46036c230805
github.com/docker/go-connections v0.4.0
github.com/docker/go-units v0.3.3 // indirect
github.com/dsnet/compress v0.0.1 // indirect
github.com/gin-gonic/gin v1.6.2
github.com/gin-gonic/gin v1.6.3
github.com/gobuffalo/envy v1.8.1 // indirect
github.com/gobuffalo/packd v1.0.0
github.com/gobuffalo/packr/v2 v2.8.0
@@ -40,7 +41,7 @@ require (
github.com/spf13/viper v1.6.3
github.com/stretchr/testify v1.5.1
github.com/ugorji/go v1.1.7 // indirect
github.com/urfave/cli v1.22.3
github.com/urfave/cli v1.22.4
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
golang.org/x/crypto v0.0.0-20191219195013-becbf705a915 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect

18
go.sum
View File

@@ -19,11 +19,16 @@ github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb0
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/VividCortex/ewma v1.1.1 h1:MnEK4VOv6n0RSY4vtRe3h11qjxL3+t0B8yOL8iMXdcM=
github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/apex/log v1.1.2 h1:bnDuVoi+o98wOdVqfEzNDlY0tcmBia7r4YkjS9EqGYk=
github.com/apex/log v1.1.2/go.mod h1:SyfRweFO+TlkIJ3DVizTSeI1xk7jOIIqOnUPZQTTsww=
github.com/apex/log v1.1.4 h1:3Zk+boorIQAAGBrHn0JUtAau4ihMamT4WdnfdnXM1zQ=
github.com/apex/log v1.1.4/go.mod h1:AlpoD9aScyQfJDVHmLMEcx4oU6LqzkWp4Mg9GdAcEvQ=
github.com/apex/logs v0.0.3/go.mod h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo=
github.com/apex/logs v0.0.4/go.mod h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo=
github.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a/go.mod h1:3NqKYiepwy8kCu4PNA+aP7WUV72eXWJeP9/r3/K9aLE=
github.com/aphistic/sweet v0.2.0/go.mod h1:fWDlIh/isSE9n6EPsRmC0det+whmX6dJid3stzu0Xys=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
@@ -35,7 +40,13 @@ github.com/briandowns/spinner v1.9.0 h1:+OMAisemaHar1hjuJ3Z2hIvNhQl9Y7GLPWUwwz2P
github.com/briandowns/spinner v1.9.0/go.mod h1://Zf9tMcxfRUA36V23M6YGEAv+kECGfvpnLTnb8n4XQ=
github.com/briandowns/spinner v1.10.0 h1:753NIJC2NHmPyVoPVWS+wh9eDx5umqe2U+JgX+KoTag=
github.com/briandowns/spinner v1.10.0/go.mod h1:QOuQk7x+EaDASo80FEXwlwiA+j/PPIcX3FScO+3/ZPQ=
github.com/briandowns/spinner v1.11.1 h1:OixPqDEcX3juo5AjQZAnFPbeUA0jvkp2qzB5gOZJ/L0=
github.com/briandowns/spinner v1.11.1/go.mod h1:QOuQk7x+EaDASo80FEXwlwiA+j/PPIcX3FScO+3/ZPQ=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cheggaaa/pb v1.0.28 h1:kWGpdAcSp3MxMU9CCHOwz/8V0kCHN4+9yQm2MzWuI98=
github.com/cheggaaa/pb v2.0.7+incompatible h1:gLKifR1UkZ/kLkda5gC0K6c8g+jU2sINPtBeOiNlMhU=
github.com/cheggaaa/pb/v3 v3.0.4 h1:QZEPYOj2ix6d5oEg63fbHmpolrnNiwjUsk+h74Yt4bM=
github.com/cheggaaa/pb/v3 v3.0.4/go.mod h1:7rgWxLrAUcFMkvJuv09+DYi7mMUYi8nO9iOWcvGJPfw=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
@@ -87,6 +98,8 @@ github.com/gin-gonic/gin v1.4.0 h1:3tMoCCfM7ppqsR0ptz/wi1impNpT7/9wQtMZ8lr1mCQ=
github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM=
github.com/gin-gonic/gin v1.6.2 h1:88crIK23zO6TqlQBt+f9FrPJNKm9ZEr7qjp9vl/d5TM=
github.com/gin-gonic/gin v1.6.2/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
@@ -240,6 +253,7 @@ github.com/mattn/go-isatty v0.0.7 h1:UvyT9uN+3r7yLEYSlJsbQGdsaB/a0DlgWP3pql6iwOc
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54=
@@ -402,6 +416,8 @@ github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo=
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli v1.22.3 h1:FpNT6zq26xNpHZy08emi755QwzLPs6Pukqjlc7RfOMU=
github.com/urfave/cli v1.22.3/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli v1.22.4 h1:u7tSpNPPswAFymm8IehJhy4uJMlUuU/GmqSkvJ1InXA=
github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo=
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
@@ -475,6 +491,8 @@ golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191223224216-5a3cf8467b4e h1:z2Flw7sLy7DxaQi3zDOvI9X+Kb06+G9iZJlkEyHvujE=
golang.org/x/sys v0.0.0-20191223224216-5a3cf8467b4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg=

View File

@@ -1,8 +1,9 @@
package middlewares
import (
"bytes"
"fmt"
"runtime"
"strings"
"time"
"github.com/apex/log"
@@ -12,7 +13,7 @@ import (
dockerDriver "github.com/metrue/fx/driver/docker"
k8sInfra "github.com/metrue/fx/driver/k8s"
"github.com/metrue/fx/provisioner"
darwin "github.com/metrue/fx/provisioner/darwin"
"github.com/metrue/fx/provisioner/darwin"
linux "github.com/metrue/fx/provisioner/linux"
"github.com/metrue/go-ssh-client"
)
@@ -32,20 +33,34 @@ func Driver(ctx context.Contexter) (err error) {
if err := driver.Ping(ctx.GetContext()); err != nil {
log.Infof("provisioning %s ...", host)
var provisioner provisioner.Provisioner
// TODO actually we should get os of target host, not the host of fx
// running on
if runtime.GOOS == "darwin" {
provisioner = darwin.New(sshClient)
} else {
provisioner = linux.New(sshClient)
}
isRemote := (host != "127.0.0.1" && host != "localhost")
if err := provisioner.Provision(ctx.GetContext(), isRemote); err != nil {
return err
hostOS := "linux"
if isRemote {
ok, err := sshClient.Connectable(provisioner.SSHConnectionTimeout)
if err != nil {
return err
}
if !ok {
return fmt.Errorf("target host could not be connected with SSH")
}
var buf bytes.Buffer
if err := sshClient.RunCommand("uname -a", ssh.CommandOptions{Stdout: &buf}); err != nil {
return err
}
hostOS = buf.String()
}
if strings.Contains(hostOS, "darwin") {
if err := darwin.New(sshClient).Provision(ctx.GetContext(), isRemote); err != nil {
return err
}
} else {
if err := linux.New(sshClient).Provision(ctx.GetContext(), isRemote); err != nil {
return err
}
}
time.Sleep(2 * time.Second)
}
time.Sleep(2 * time.Second)
if err := docker.Initialize(); err != nil {
return fmt.Errorf("initialize docker client failed: %s", err)
}

View File

@@ -52,7 +52,8 @@ users:
defer os.Remove(kubeconf.Name())
sshClient := sshMocks.NewMockClienter(ctrl)
sshClient.EXPECT().Connectable(10*time.Second).Return(true, nil).Times(2)
sshClient.EXPECT().Connectable(10*time.Second).Return(true, nil).Times(3)
sshClient.EXPECT().RunCommand("uname -a", gomock.Any()).Return(nil)
sshClient.EXPECT().RunCommand("docker version", ssh.CommandOptions{
Timeout: 10 * time.Second,
}).Return(nil)

View File

@@ -29,7 +29,6 @@ func set(ctx context.Contexter, cli *cli.Context, fields []argsField) error {
ctx.Set("host", ip)
ctx.Set("user", user)
} else {
ctx.Set(f.Name, cli.String(f.Name))
}
} else if f.Type == "int" {

View File

@@ -44,7 +44,7 @@ func TreeToDir(tree map[string]string, outputDir string) error {
if err := utils.EnsureFile(fn); err != nil {
return err
}
if err := ioutil.WriteFile(fn, []byte(v), 0666); err != nil {
if err := ioutil.WriteFile(fn, []byte(v), 0600); err != nil {
return err
}
}

View File

@@ -2,48 +2,42 @@ package spinner
import (
"fmt"
"math/rand"
"time"
"github.com/briandowns/spinner"
aurora "github.com/logrusorgru/aurora"
"github.com/cheggaaa/pb/v3"
"github.com/logrusorgru/aurora"
)
var s *spinner.Spinner
var bars map[string]*pb.ProgressBar
func init() {
style := spinner.CharSets[36]
interval := 100 * time.Millisecond
s = spinner.New(style, interval)
bars = make(map[string]*pb.ProgressBar)
}
// Start spinner
func Start(task string) {
colors := []string{
"red",
"green",
"yellow",
"blue",
"magenta",
"cyan",
"white",
}
rand.Seed(time.Now().UnixNano())
// nolint
s.Color(colors[rand.Intn(len(colors))])
s.Prefix = task + " "
if s.Active() {
s.Restart()
} else {
s.Start()
count := 100
b, ok := bars[task]
if !ok {
b = pb.StartNew(count)
bars[task] = b
}
go func() {
fmt.Printf("Starting %s\n", task)
for i := 0; i < count; i++ {
b.Increment()
time.Sleep(50 * time.Millisecond)
}
}()
}
// Stop spinner
func Stop(task string, err error) {
if err != nil {
fmt.Println(aurora.Red("\u2717"))
b, ok := bars[task]
if ok {
b.Finish()
}
if err != nil {
fmt.Printf("%s: %s\n", task, aurora.Red("\u2717"))
}
s.Stop()
}

View File

@@ -6,14 +6,11 @@ import (
"fmt"
"os/exec"
"strings"
"time"
"github.com/metrue/fx/provisioner"
"github.com/metrue/go-ssh-client"
)
const sshConnectionTimeout = 10 * time.Second
var scripts = map[string]string{
"docker_version": "docker version",
"has_docker": "type docker",
@@ -52,7 +49,7 @@ func (d *Docker) Provision(ctx context.Context, isRemote bool) error {
func (d *Docker) runCmd(script string, isRemote bool, options ...ssh.CommandOptions) error {
option := ssh.CommandOptions{
Timeout: sshConnectionTimeout,
Timeout: provisioner.SSHConnectionTimeout,
}
if len(options) >= 1 {
option = options[0]
@@ -72,7 +69,7 @@ func (d *Docker) runCmd(script string, isRemote bool, options ...ssh.CommandOpti
}
return nil
}
ok, err := d.sshClient.Connectable(sshConnectionTimeout)
ok, err := d.sshClient.Connectable(provisioner.SSHConnectionTimeout)
if err != nil {
return fmt.Errorf("could not connect via SSH: '%s'", err)
}

View File

@@ -6,6 +6,7 @@ import (
"testing"
"github.com/golang/mock/gomock"
"github.com/metrue/fx/provisioner"
"github.com/metrue/go-ssh-client"
sshMocks "github.com/metrue/go-ssh-client/mocks"
)
@@ -18,7 +19,7 @@ func TestDriverProvision(t *testing.T) {
sshClient := sshMocks.NewMockClienter(ctrl)
n := &Docker{sshClient: sshClient}
err := errors.New("could not connect to host")
sshClient.EXPECT().Connectable(sshConnectionTimeout).Return(false, err).AnyTimes()
sshClient.EXPECT().Connectable(provisioner.SSHConnectionTimeout).Return(false, err).AnyTimes()
if err := n.Provision(context.Background(), true); err == nil {
t.Fatalf("should get error when SSH connection not ok")
}
@@ -30,7 +31,7 @@ func TestDriverProvision(t *testing.T) {
sshClient := sshMocks.NewMockClienter(ctrl)
n := New(sshClient)
sshClient.EXPECT().Connectable(sshConnectionTimeout).Return(false, nil).AnyTimes()
sshClient.EXPECT().Connectable(provisioner.SSHConnectionTimeout).Return(false, nil).AnyTimes()
if err := n.Provision(context.Background(), true); err == nil {
t.Fatalf("should get error when SSH connection not ok")
}
@@ -42,9 +43,9 @@ func TestDriverProvision(t *testing.T) {
sshClient := sshMocks.NewMockClienter(ctrl)
n := New(sshClient)
sshClient.EXPECT().Connectable(sshConnectionTimeout).Return(true, nil).AnyTimes()
sshClient.EXPECT().RunCommand(scripts["docker_version"], ssh.CommandOptions{Timeout: sshConnectionTimeout}).Return(nil)
sshClient.EXPECT().RunCommand(scripts["check_fx_agent"], ssh.CommandOptions{Timeout: sshConnectionTimeout}).Return(nil)
sshClient.EXPECT().Connectable(provisioner.SSHConnectionTimeout).Return(true, nil).AnyTimes()
sshClient.EXPECT().RunCommand(scripts["docker_version"], ssh.CommandOptions{Timeout: provisioner.SSHConnectionTimeout}).Return(nil)
sshClient.EXPECT().RunCommand(scripts["check_fx_agent"], ssh.CommandOptions{Timeout: provisioner.SSHConnectionTimeout}).Return(nil)
if err := n.Provision(context.Background(), true); err != nil {
t.Fatal(err)
}
@@ -56,10 +57,10 @@ func TestDriverProvision(t *testing.T) {
sshClient := sshMocks.NewMockClienter(ctrl)
n := New(sshClient)
sshClient.EXPECT().Connectable(sshConnectionTimeout).Return(true, nil).AnyTimes()
sshClient.EXPECT().Connectable(provisioner.SSHConnectionTimeout).Return(true, nil).AnyTimes()
err := errors.New("docker command not found")
sshClient.EXPECT().RunCommand(scripts["docker_version"], ssh.CommandOptions{Timeout: sshConnectionTimeout}).Return(err)
sshClient.EXPECT().RunCommand(scripts["has_docker"], ssh.CommandOptions{Timeout: sshConnectionTimeout}).Return(err)
sshClient.EXPECT().RunCommand(scripts["docker_version"], ssh.CommandOptions{Timeout: provisioner.SSHConnectionTimeout}).Return(err)
sshClient.EXPECT().RunCommand(scripts["has_docker"], ssh.CommandOptions{Timeout: provisioner.SSHConnectionTimeout}).Return(err)
if err := n.Provision(context.Background(), true); err == nil {
t.Fatal("should tell user to install docker first")
}
@@ -71,11 +72,11 @@ func TestDriverProvision(t *testing.T) {
sshClient := sshMocks.NewMockClienter(ctrl)
n := New(sshClient)
sshClient.EXPECT().Connectable(sshConnectionTimeout).Return(true, nil).AnyTimes()
sshClient.EXPECT().Connectable(provisioner.SSHConnectionTimeout).Return(true, nil).AnyTimes()
err := errors.New("fx agent not found")
sshClient.EXPECT().RunCommand(scripts["docker_version"], ssh.CommandOptions{Timeout: sshConnectionTimeout}).Return(nil)
sshClient.EXPECT().RunCommand(scripts["check_fx_agent"], ssh.CommandOptions{Timeout: sshConnectionTimeout}).Return(err)
sshClient.EXPECT().RunCommand(scripts["start_fx_agent"], ssh.CommandOptions{Timeout: sshConnectionTimeout}).Return(nil)
sshClient.EXPECT().RunCommand(scripts["docker_version"], ssh.CommandOptions{Timeout: provisioner.SSHConnectionTimeout}).Return(nil)
sshClient.EXPECT().RunCommand(scripts["check_fx_agent"], ssh.CommandOptions{Timeout: provisioner.SSHConnectionTimeout}).Return(err)
sshClient.EXPECT().RunCommand(scripts["start_fx_agent"], ssh.CommandOptions{Timeout: provisioner.SSHConnectionTimeout}).Return(nil)
if err := n.Provision(context.Background(), true); err != nil {
t.Fatal(err)
}
@@ -88,9 +89,9 @@ func TestDriverProvision(t *testing.T) {
sshClient := sshMocks.NewMockClienter(ctrl)
n := New(sshClient)
sshClient.EXPECT().Connectable(sshConnectionTimeout).Return(true, nil).AnyTimes()
sshClient.EXPECT().RunCommand(scripts["docker_version"], ssh.CommandOptions{Timeout: sshConnectionTimeout}).Return(nil)
sshClient.EXPECT().RunCommand(scripts["check_fx_agent"], ssh.CommandOptions{Timeout: sshConnectionTimeout}).Return(nil)
sshClient.EXPECT().Connectable(provisioner.SSHConnectionTimeout).Return(true, nil).AnyTimes()
sshClient.EXPECT().RunCommand(scripts["docker_version"], ssh.CommandOptions{Timeout: provisioner.SSHConnectionTimeout}).Return(nil)
sshClient.EXPECT().RunCommand(scripts["check_fx_agent"], ssh.CommandOptions{Timeout: provisioner.SSHConnectionTimeout}).Return(nil)
if err := n.Provision(context.Background(), true); err != nil {
t.Fatal(err)
}
@@ -107,9 +108,9 @@ func TestRunCommand(t *testing.T) {
}
script := "script"
option := ssh.CommandOptions{
Timeout: sshConnectionTimeout,
Timeout: provisioner.SSHConnectionTimeout,
}
sshClient.EXPECT().Connectable(sshConnectionTimeout).Return(true, nil)
sshClient.EXPECT().Connectable(provisioner.SSHConnectionTimeout).Return(true, nil)
sshClient.EXPECT().RunCommand(script, option).Return(nil)
if err := n.runCmd(script, true, option); err != nil {
t.Fatal(err)

View File

@@ -5,14 +5,11 @@ import (
"fmt"
"os/exec"
"strings"
"time"
"github.com/metrue/fx/provisioner"
"github.com/metrue/go-ssh-client"
)
const sshConnectionTimeout = 10 * time.Second
var scripts = map[string]interface{}{
"docker_version": "docker version",
"has_docker": "type docker",
@@ -58,7 +55,7 @@ func (d *Docker) Provision(ctx context.Context, isRemote bool) error {
func (d *Docker) runCmd(script string, isRemote bool, options ...ssh.CommandOptions) error {
option := ssh.CommandOptions{
Timeout: sshConnectionTimeout,
Timeout: provisioner.SSHConnectionTimeout,
}
if len(options) >= 1 {
option = options[0]
@@ -78,7 +75,7 @@ func (d *Docker) runCmd(script string, isRemote bool, options ...ssh.CommandOpti
}
return nil
}
ok, err := d.sshClient.Connectable(sshConnectionTimeout)
ok, err := d.sshClient.Connectable(provisioner.SSHConnectionTimeout)
if err != nil {
return fmt.Errorf("could not connect via SSH: '%s'", err)
}

View File

@@ -6,6 +6,7 @@ import (
"testing"
"github.com/golang/mock/gomock"
"github.com/metrue/fx/provisioner"
"github.com/metrue/go-ssh-client"
sshMocks "github.com/metrue/go-ssh-client/mocks"
)
@@ -18,7 +19,7 @@ func TestDriverProvision(t *testing.T) {
sshClient := sshMocks.NewMockClienter(ctrl)
n := &Docker{sshClient: sshClient}
err := errors.New("could not connect to host")
sshClient.EXPECT().Connectable(sshConnectionTimeout).Return(false, err).AnyTimes()
sshClient.EXPECT().Connectable(provisioner.SSHConnectionTimeout).Return(false, err).AnyTimes()
if err := n.Provision(context.Background(), true); err == nil {
t.Fatalf("should get error when SSH connection not ok")
}
@@ -30,7 +31,7 @@ func TestDriverProvision(t *testing.T) {
sshClient := sshMocks.NewMockClienter(ctrl)
n := New(sshClient)
sshClient.EXPECT().Connectable(sshConnectionTimeout).Return(false, nil).AnyTimes()
sshClient.EXPECT().Connectable(provisioner.SSHConnectionTimeout).Return(false, nil).AnyTimes()
if err := n.Provision(context.Background(), true); err == nil {
t.Fatalf("should get error when SSH connection not ok")
}
@@ -42,9 +43,9 @@ func TestDriverProvision(t *testing.T) {
sshClient := sshMocks.NewMockClienter(ctrl)
n := New(sshClient)
sshClient.EXPECT().Connectable(sshConnectionTimeout).Return(true, nil).AnyTimes()
sshClient.EXPECT().RunCommand(scripts["docker_version"].(string), ssh.CommandOptions{Timeout: sshConnectionTimeout}).Return(nil)
sshClient.EXPECT().RunCommand(scripts["check_fx_agent"].(string), ssh.CommandOptions{Timeout: sshConnectionTimeout}).Return(nil)
sshClient.EXPECT().Connectable(provisioner.SSHConnectionTimeout).Return(true, nil).AnyTimes()
sshClient.EXPECT().RunCommand(scripts["docker_version"].(string), ssh.CommandOptions{Timeout: provisioner.SSHConnectionTimeout}).Return(nil)
sshClient.EXPECT().RunCommand(scripts["check_fx_agent"].(string), ssh.CommandOptions{Timeout: provisioner.SSHConnectionTimeout}).Return(nil)
if err := n.Provision(context.Background(), true); err != nil {
t.Fatal(err)
}
@@ -56,13 +57,13 @@ func TestDriverProvision(t *testing.T) {
sshClient := sshMocks.NewMockClienter(ctrl)
n := New(sshClient)
sshClient.EXPECT().Connectable(sshConnectionTimeout).Return(true, nil).AnyTimes()
sshClient.EXPECT().Connectable(provisioner.SSHConnectionTimeout).Return(true, nil).AnyTimes()
err := errors.New("docker command not found")
sshClient.EXPECT().RunCommand(scripts["docker_version"].(string), ssh.CommandOptions{Timeout: sshConnectionTimeout}).Return(err)
sshClient.EXPECT().RunCommand(scripts["has_docker"].(string), ssh.CommandOptions{Timeout: sshConnectionTimeout}).Return(err)
sshClient.EXPECT().RunCommand(scripts["install_docker"].(string), ssh.CommandOptions{Timeout: sshConnectionTimeout}).Return(nil)
sshClient.EXPECT().RunCommand(scripts["start_dockerd"].(string), ssh.CommandOptions{Timeout: sshConnectionTimeout}).Return(nil)
sshClient.EXPECT().RunCommand(scripts["check_fx_agent"].(string), ssh.CommandOptions{Timeout: sshConnectionTimeout}).Return(nil)
sshClient.EXPECT().RunCommand(scripts["docker_version"].(string), ssh.CommandOptions{Timeout: provisioner.SSHConnectionTimeout}).Return(err)
sshClient.EXPECT().RunCommand(scripts["has_docker"].(string), ssh.CommandOptions{Timeout: provisioner.SSHConnectionTimeout}).Return(err)
sshClient.EXPECT().RunCommand(scripts["install_docker"].(string), ssh.CommandOptions{Timeout: provisioner.SSHConnectionTimeout}).Return(nil)
sshClient.EXPECT().RunCommand(scripts["start_dockerd"].(string), ssh.CommandOptions{Timeout: provisioner.SSHConnectionTimeout}).Return(nil)
sshClient.EXPECT().RunCommand(scripts["check_fx_agent"].(string), ssh.CommandOptions{Timeout: provisioner.SSHConnectionTimeout}).Return(nil)
if err := n.Provision(context.Background(), true); err != nil {
t.Fatal(err)
}
@@ -74,11 +75,11 @@ func TestDriverProvision(t *testing.T) {
sshClient := sshMocks.NewMockClienter(ctrl)
n := New(sshClient)
sshClient.EXPECT().Connectable(sshConnectionTimeout).Return(true, nil).AnyTimes()
sshClient.EXPECT().Connectable(provisioner.SSHConnectionTimeout).Return(true, nil).AnyTimes()
err := errors.New("fx agent not found")
sshClient.EXPECT().RunCommand(scripts["docker_version"].(string), ssh.CommandOptions{Timeout: sshConnectionTimeout}).Return(nil)
sshClient.EXPECT().RunCommand(scripts["check_fx_agent"].(string), ssh.CommandOptions{Timeout: sshConnectionTimeout}).Return(err)
sshClient.EXPECT().RunCommand(scripts["start_fx_agent"].(string), ssh.CommandOptions{Timeout: sshConnectionTimeout}).Return(nil)
sshClient.EXPECT().RunCommand(scripts["docker_version"].(string), ssh.CommandOptions{Timeout: provisioner.SSHConnectionTimeout}).Return(nil)
sshClient.EXPECT().RunCommand(scripts["check_fx_agent"].(string), ssh.CommandOptions{Timeout: provisioner.SSHConnectionTimeout}).Return(err)
sshClient.EXPECT().RunCommand(scripts["start_fx_agent"].(string), ssh.CommandOptions{Timeout: provisioner.SSHConnectionTimeout}).Return(nil)
if err := n.Provision(context.Background(), true); err != nil {
t.Fatal(err)
}
@@ -91,15 +92,15 @@ func TestDriverProvision(t *testing.T) {
sshClient := sshMocks.NewMockClienter(ctrl)
n := New(sshClient)
sshClient.EXPECT().Connectable(sshConnectionTimeout).Return(true, nil).AnyTimes()
sshClient.EXPECT().Connectable(provisioner.SSHConnectionTimeout).Return(true, nil).AnyTimes()
err2 := errors.New("fx agent not found")
err1 := errors.New("docker command not found")
sshClient.EXPECT().RunCommand(scripts["docker_version"].(string), ssh.CommandOptions{Timeout: sshConnectionTimeout}).Return(err1)
sshClient.EXPECT().RunCommand(scripts["has_docker"].(string), ssh.CommandOptions{Timeout: sshConnectionTimeout}).Return(err1)
sshClient.EXPECT().RunCommand(scripts["install_docker"].(string), ssh.CommandOptions{Timeout: sshConnectionTimeout}).Return(nil)
sshClient.EXPECT().RunCommand(scripts["start_dockerd"].(string), ssh.CommandOptions{Timeout: sshConnectionTimeout}).Return(nil)
sshClient.EXPECT().RunCommand(scripts["check_fx_agent"].(string), ssh.CommandOptions{Timeout: sshConnectionTimeout}).Return(err2)
sshClient.EXPECT().RunCommand(scripts["start_fx_agent"].(string), ssh.CommandOptions{Timeout: sshConnectionTimeout}).Return(nil)
sshClient.EXPECT().RunCommand(scripts["docker_version"].(string), ssh.CommandOptions{Timeout: provisioner.SSHConnectionTimeout}).Return(err1)
sshClient.EXPECT().RunCommand(scripts["has_docker"].(string), ssh.CommandOptions{Timeout: provisioner.SSHConnectionTimeout}).Return(err1)
sshClient.EXPECT().RunCommand(scripts["install_docker"].(string), ssh.CommandOptions{Timeout: provisioner.SSHConnectionTimeout}).Return(nil)
sshClient.EXPECT().RunCommand(scripts["start_dockerd"].(string), ssh.CommandOptions{Timeout: provisioner.SSHConnectionTimeout}).Return(nil)
sshClient.EXPECT().RunCommand(scripts["check_fx_agent"].(string), ssh.CommandOptions{Timeout: provisioner.SSHConnectionTimeout}).Return(err2)
sshClient.EXPECT().RunCommand(scripts["start_fx_agent"].(string), ssh.CommandOptions{Timeout: provisioner.SSHConnectionTimeout}).Return(nil)
if err := n.Provision(context.Background(), true); err != nil {
t.Fatal(err)
}
@@ -116,9 +117,9 @@ func TestRunCommand(t *testing.T) {
}
script := "script"
option := ssh.CommandOptions{
Timeout: sshConnectionTimeout,
Timeout: provisioner.SSHConnectionTimeout,
}
sshClient.EXPECT().Connectable(sshConnectionTimeout).Return(true, nil)
sshClient.EXPECT().Connectable(provisioner.SSHConnectionTimeout).Return(true, nil)
sshClient.EXPECT().RunCommand(script, option).Return(nil)
if err := n.runCmd(script, true, option); err != nil {
t.Fatal(err)

View File

@@ -1,6 +1,12 @@
package provisioner
import "context"
import (
"context"
"time"
)
// SSHConnectionTimeout default timeout for ssh connection
const SSHConnectionTimeout = 10 * time.Second
// Provisioner define provisioner interface
type Provisioner interface {

View File

@@ -26,7 +26,7 @@ func Merge(dest string, input ...string) error {
if err != nil {
return err
}
if err := ioutil.WriteFile(targetFilePath, body, 0644); err != nil {
if err := ioutil.WriteFile(targetFilePath, body, 0600); err != nil {
return err
}
} else if stat.Mode().IsDir() {

View File

@@ -29,6 +29,7 @@ func Download(filepath string, url string) (err error) {
}
defer resp.Body.Close()
// nolint: gosec
_, err = io.Copy(out, resp.Body)
if err != nil {
return err
@@ -70,6 +71,7 @@ func Unzip(source string, target string) (err error) {
}
defer targetFile.Close()
// nolint: gosec
if _, err := io.Copy(targetFile, fileReader); err != nil {
return err
}
@@ -96,6 +98,7 @@ func CopyFile(src, dst string) (err error) {
}
}()
// nolint: gosec
_, err = io.Copy(out, in)
if err != nil {
return