diff --git a/cmd/deploy/deploy.go b/cmd/deploy/deploy.go
index 426d597a..5726756c 100644
--- a/cmd/deploy/deploy.go
+++ b/cmd/deploy/deploy.go
@@ -31,10 +31,11 @@ func main() {
}
func doDeploy() int {
- var context, namespace string
+ var context, namespace, timeout string
const (
contextUsage = "override the context for default environment deployment target"
namespaceUsage = "override the namespace for default environment deployment target"
+ timeoutUsage = "override the default deployment timeout (2 minutes). 0 means forever, all other values should contain a corresponding time unit (e.g. 1s, 2m, 3h)"
)
set := flag.NewFlagSet("deploy", flag.ExitOnError)
set.Usage = func() {
@@ -45,6 +46,8 @@ func doDeploy() int {
set.StringVar(&context, "c", "", contextUsage+" (shorthand)")
set.StringVar(&namespace, "namespace", "", namespaceUsage)
set.StringVar(&namespace, "n", "", namespaceUsage+" (shorthand)")
+ set.StringVar(&timeout, "timeout", "", timeoutUsage)
+ set.StringVar(&timeout, "t", "", timeoutUsage+" (shorthand)")
_ = set.Parse(os.Args[1:])
if set.NArg() < 1 {
set.Usage()
@@ -67,6 +70,9 @@ func doDeploy() int {
if namespace != "" {
env.Namespace = namespace
}
+ if timeout == "" {
+ timeout = "2m"
+ }
currentCI := cfg.CurrentCI()
if !ci.IsValid(currentCI) {
_, _ = fmt.Println(tml.Sprintf("Commit and/or branch information is missing. Perhaps your not in a Git repository or forgot to set environment variables?"))
@@ -76,7 +82,7 @@ func doDeploy() int {
tstamp := time.Now().Format(time.RFC3339)
client := kubectl.New(env, os.Stdout, os.Stderr)
defer client.Cleanup()
- if err := deploy.Deploy(dir, currentCI.Commit(), currentCI.BuildName(), tstamp, environment, client, os.Stdout, os.Stderr); err != nil {
+ if err := deploy.Deploy(dir, currentCI.Commit(), currentCI.BuildName(), tstamp, environment, client, os.Stdout, os.Stderr, timeout); err != nil {
fmt.Println(err.Error())
return -4
}
diff --git a/cmd/deploy/deploy_test.go b/cmd/deploy/deploy_test.go
index 1900cf82..4bd6573a 100644
--- a/cmd/deploy/deploy_test.go
+++ b/cmd/deploy/deploy_test.go
@@ -163,3 +163,30 @@ environments:
os.Args = []string{"deploy", "-c", "other", "-n", "dev", "dummy"}
main()
}
+
+func TestDeploy_Timeout(t *testing.T) {
+ exitFunc = func(code int) {
+ assert.Equal(t, -4, code)
+ }
+
+ defer pkg.SetEnv("CI_COMMIT_SHA", "abc123")()
+ defer pkg.SetEnv("CI_PROJECT_NAME", "dummy")()
+ defer pkg.SetEnv("CI_COMMIT_REF_NAME", "master")()
+ oldPwd, _ := os.Getwd()
+ name, _ := ioutil.TempDir(os.TempDir(), "build-tools")
+ defer func() { _ = os.RemoveAll(name) }()
+ yaml := `
+environments:
+ dummy:
+ context: missing
+ namespace: none
+`
+ _ = ioutil.WriteFile(filepath.Join(name, ".buildtools.yaml"), []byte(yaml), 0777)
+
+ err := os.Chdir(name)
+ assert.NoError(t, err)
+ defer func() { _ = os.Chdir(oldPwd) }()
+
+ os.Args = []string{"deploy", "-t", "20s", "dummy"}
+ main()
+}
diff --git a/pkg/deploy/deploy.go b/pkg/deploy/deploy.go
index d671429c..a7152f5c 100644
--- a/pkg/deploy/deploy.go
+++ b/pkg/deploy/deploy.go
@@ -11,14 +11,14 @@ import (
"strings"
)
-func Deploy(dir, commit, buildName, timestamp, targetEnvironment string, client kubectl.Kubectl, out, eout io.Writer) error {
+func Deploy(dir, commit, buildName, timestamp, targetEnvironment string, client kubectl.Kubectl, out, eout io.Writer, timeout string) error {
deploymentFiles := filepath.Join(dir, "k8s")
if err := processDir(deploymentFiles, commit, timestamp, targetEnvironment, client, out, eout); err != nil {
return err
}
if client.DeploymentExists(buildName) {
- if !client.RolloutStatus(buildName) {
+ if !client.RolloutStatus(buildName, timeout) {
_, _ = fmt.Fprint(out, "Rollout failed. Fetching events.")
_, _ = fmt.Fprint(out, client.DeploymentEvents(buildName))
_, _ = fmt.Fprint(out, client.PodEvents(buildName))
diff --git a/pkg/deploy/deploy_test.go b/pkg/deploy/deploy_test.go
index bcf13c8c..0bc74832 100644
--- a/pkg/deploy/deploy_test.go
+++ b/pkg/deploy/deploy_test.go
@@ -20,7 +20,7 @@ func TestDeploy_MissingDeploymentFilesDir(t *testing.T) {
out := &bytes.Buffer{}
eout := &bytes.Buffer{}
- err := Deploy(".", "abc123", "image", "20190513-17:22:36", "test", client, out, eout)
+ err := Deploy(".", "abc123", "image", "20190513-17:22:36", "test", client, out, eout, "2m")
assert.EqualError(t, err, "open k8s: no such file or directory")
assert.Equal(t, "", out.String())
@@ -38,7 +38,7 @@ func TestDeploy_NoFiles(t *testing.T) {
out := &bytes.Buffer{}
eout := &bytes.Buffer{}
- err := Deploy(name, "abc123", "image", "20190513-17:22:36", "test", client, out, eout)
+ err := Deploy(name, "abc123", "image", "20190513-17:22:36", "test", client, out, eout, "2m")
assert.NoError(t, err)
assert.Equal(t, 0, len(client.Inputs))
@@ -65,7 +65,7 @@ metadata:
out := &bytes.Buffer{}
eout := &bytes.Buffer{}
- err := Deploy(name, "abc123", "image", "20190513-17:22:36", "test", client, out, eout)
+ err := Deploy(name, "abc123", "image", "20190513-17:22:36", "test", client, out, eout, "2m")
assert.NoError(t, err)
assert.Equal(t, 1, len(client.Inputs))
@@ -85,7 +85,7 @@ func TestDeploy_UnreadableFile(t *testing.T) {
out := &bytes.Buffer{}
eout := &bytes.Buffer{}
- err := Deploy(name, "abc123", "image", "20190513-17:22:36", "test", client, out, eout)
+ err := Deploy(name, "abc123", "image", "20190513-17:22:36", "test", client, out, eout, "2m")
assert.EqualError(t, err, fmt.Sprintf("read %s/k8s/deploy.yaml: is a directory", name))
assert.Equal(t, "", out.String())
@@ -107,7 +107,7 @@ func TestDeploy_FileBrokenSymlink(t *testing.T) {
out := &bytes.Buffer{}
eout := &bytes.Buffer{}
- err := Deploy(name, "abc123", "image", "20190513-17:22:36", "test", client, out, eout)
+ err := Deploy(name, "abc123", "image", "20190513-17:22:36", "test", client, out, eout, "2m")
assert.EqualError(t, err, fmt.Sprintf("open %s/k8s/deploy.yaml: no such file or directory", name))
assert.Equal(t, "", out.String())
@@ -133,7 +133,7 @@ metadata:
out := &bytes.Buffer{}
eout := &bytes.Buffer{}
- err := Deploy(name, "abc123", "image", "20190513-17:22:36", "dummy", client, out, eout)
+ err := Deploy(name, "abc123", "image", "20190513-17:22:36", "dummy", client, out, eout, "2m")
assert.NoError(t, err)
assert.Equal(t, 1, len(client.Inputs))
@@ -157,7 +157,7 @@ func TestDeploy_EnvSpecificFiles(t *testing.T) {
out := &bytes.Buffer{}
eout := &bytes.Buffer{}
- err := Deploy(name, "abc123", "image", "20190513-17:22:36", "prod", client, out, eout)
+ err := Deploy(name, "abc123", "image", "20190513-17:22:36", "prod", client, out, eout, "2m")
assert.NoError(t, err)
assert.Equal(t, 1, len(client.Inputs))
@@ -180,7 +180,7 @@ echo "Prod-script with suffix"`
out := &bytes.Buffer{}
eout := &bytes.Buffer{}
- err := Deploy(name, "abc123", "image", "20190513-17:22:36", "prod", client, out, eout)
+ err := Deploy(name, "abc123", "image", "20190513-17:22:36", "prod", client, out, eout, "2m")
assert.NoError(t, err)
assert.Equal(t, 0, len(client.Inputs))
@@ -202,7 +202,7 @@ echo "Script without suffix should not execute"`
out := &bytes.Buffer{}
eout := &bytes.Buffer{}
- err := Deploy(name, "abc123", "image", "20190513-17:22:36", "prod", client, out, eout)
+ err := Deploy(name, "abc123", "image", "20190513-17:22:36", "prod", client, out, eout, "2m")
assert.NoError(t, err)
assert.Equal(t, 0, len(client.Inputs))
@@ -225,7 +225,7 @@ echo "Prod-script with suffix"`
out := &bytes.Buffer{}
eout := &bytes.Buffer{}
- err := Deploy(name, "abc123", "image", "20190513-17:22:36", "prod", client, out, eout)
+ err := Deploy(name, "abc123", "image", "20190513-17:22:36", "prod", client, out, eout, "2m")
assert.EqualError(t, err, fmt.Sprintf("fork/exec %s: permission denied", scriptName))
}
@@ -249,7 +249,7 @@ metadata:
out := &bytes.Buffer{}
eout := &bytes.Buffer{}
- err := Deploy(name, "abc123", "image", "20190513-17:22:36", "test", client, out, eout)
+ err := Deploy(name, "abc123", "image", "20190513-17:22:36", "test", client, out, eout, "2m")
assert.EqualError(t, err, "apply failed")
assert.Equal(t, "", out.String())
@@ -277,7 +277,7 @@ metadata:
out := &bytes.Buffer{}
eout := &bytes.Buffer{}
- err := Deploy(name, "abc123", "image", "2019-05-13T17:22:36Z01:00", "test", client, out, eout)
+ err := Deploy(name, "abc123", "image", "2019-05-13T17:22:36Z01:00", "test", client, out, eout, "2m")
assert.NoError(t, err)
assert.Equal(t, 1, len(client.Inputs))
@@ -314,7 +314,7 @@ metadata:
out := &bytes.Buffer{}
eout := &bytes.Buffer{}
- err := Deploy(name, "abc123", "image", "20190513-17:22:36", "test", client, out, eout)
+ err := Deploy(name, "abc123", "image", "20190513-17:22:36", "test", client, out, eout, "2m")
assert.EqualError(t, err, "failed to rollout")
assert.Equal(t, 1, len(client.Inputs))
@@ -344,7 +344,7 @@ metadata:
out := &bytes.Buffer{}
eout := &bytes.Buffer{}
- err := Deploy(name, "abc123", "image", "20190513-17:22:36", "test", client, out, eout)
+ err := Deploy(name, "abc123", "image", "20190513-17:22:36", "test", client, out, eout, "2m")
assert.EqualError(t, err, "failed to rollout")
assert.Equal(t, 1, len(client.Inputs))
diff --git a/pkg/kubectl/kubectl.go b/pkg/kubectl/kubectl.go
index b9f267da..70faa992 100644
--- a/pkg/kubectl/kubectl.go
+++ b/pkg/kubectl/kubectl.go
@@ -23,7 +23,7 @@ type Kubectl interface {
Apply(input string) error
Cleanup()
DeploymentExists(name string) bool
- RolloutStatus(name string) bool
+ RolloutStatus(name, timeout string) bool
DeploymentEvents(name string) string
PodEvents(name string) string
}
@@ -114,9 +114,9 @@ func (k kubectl) DeploymentExists(name string) bool {
return c.Execute() == nil
}
-func (k kubectl) RolloutStatus(name string) bool {
+func (k kubectl) RolloutStatus(name, timeout string) bool {
args := k.defaultArgs()
- args = append(args, "rollout", "status", "deployment", "--timeout=2m", name)
+ args = append(args, "rollout", "status", "deployment", fmt.Sprintf("--timeout=%s", timeout), name)
_, _ = fmt.Fprintf(k.out, "kubectl %s\n", strings.Join(args, " "))
c := newKubectlCmd(os.Stdin, os.Stdout, os.Stderr)
c.SetArgs(args)
diff --git a/pkg/kubectl/kubectl_test.go b/pkg/kubectl/kubectl_test.go
index ae9ff899..669f9034 100644
--- a/pkg/kubectl/kubectl_test.go
+++ b/pkg/kubectl/kubectl_test.go
@@ -147,7 +147,7 @@ func TestKubectl_RolloutStatusSuccess(t *testing.T) {
k := New(&config.Environment{Context: "missing", Namespace: "default"}, out, eout)
- result := k.RolloutStatus("image")
+ result := k.RolloutStatus("image", "2m")
assert.True(t, result)
assert.Equal(t, 1, len(calls))
assert.Equal(t, []string{"rollout", "status", "deployment", "image", "--context", "missing", "--namespace", "default", "--timeout", "2m0s"}, calls[0])
@@ -165,7 +165,7 @@ func TestKubectl_RolloutStatusFailure(t *testing.T) {
k := New(&config.Environment{Context: "missing", Namespace: "default"}, out, eout)
- result := k.RolloutStatus("image")
+ result := k.RolloutStatus("image", "2m")
assert.False(t, result)
assert.Equal(t, 1, len(calls))
assert.Equal(t, []string{"rollout", "status", "deployment", "image", "--context", "missing", "--namespace", "default", "--timeout", "2m0s"}, calls[0])
@@ -186,11 +186,11 @@ func TestKubectl_RolloutStatusFatal(t *testing.T) {
k := New(&config.Environment{Context: "missing", Namespace: "default"}, out, eout)
- result := k.RolloutStatus("image")
+ result := k.RolloutStatus("image", "3m")
assert.False(t, result)
assert.Equal(t, 1, len(calls))
- assert.Equal(t, []string{"rollout", "status", "deployment", "image", "--context", "missing", "--namespace", "default", "--timeout", "2m0s"}, calls[0])
- assert.Equal(t, "kubectl --context missing --namespace default rollout status deployment --timeout=2m image\n", out.String())
+ assert.Equal(t, []string{"rollout", "status", "deployment", "image", "--context", "missing", "--namespace", "default", "--timeout", "3m0s"}, calls[0])
+ assert.Equal(t, "kubectl --context missing --namespace default rollout status deployment --timeout=3m image\n", out.String())
assert.Equal(t, "failed to get kubeconfig from environment\n", eout.String())
}
diff --git a/pkg/kubectl/testing.go b/pkg/kubectl/testing.go
index 5427c9e9..6125de13 100644
--- a/pkg/kubectl/testing.go
+++ b/pkg/kubectl/testing.go
@@ -21,7 +21,7 @@ func (m *MockKubectl) DeploymentExists(name string) bool {
return m.Deployment
}
-func (m *MockKubectl) RolloutStatus(name string) bool {
+func (m *MockKubectl) RolloutStatus(name, timeout string) bool {
return m.Status
}
diff --git a/www/content/commands.md b/www/content/commands.md
index 819fae9b..0270ad69 100644
--- a/www/content/commands.md
+++ b/www/content/commands.md
@@ -38,10 +38,11 @@ $ push -f docker/Dockerfile.build
Deploys the built application to a Kubernetes cluster. Normal usage `deploy `, but additional flags can be used to override:
-| Flag | Description |
-| :--------------------------------- | :------------------------------------------------------------ |
-| `-c/--context` | Use a different context than the one found in configuration |
-| `-n/--namespace` | Use a different namespace than the one found in configuration |
+| Flag | Description |
+| :--------------------------------- | :-------------------------------------------------------------------------------|
+| `-c/--context` | Use a different context than the one found in configuration |
+| `-n/--namespace` | Use a different namespace than the one found in configuration |
+| `-t/--timeout` | Override the default deployment waiting time for completion (default 2 minutes). 0 means forever, all other values should contain a corresponding time unit (e.g. 1s, 2m, 3h) |
```sh
$ deploy -n testing_namespace local