Skip to content

Commit 2944714

Browse files
committed
Merge pull request #136 from aledbf/add-timeouts
feat(builder): make the builder pod timeout configurable
2 parents e05345f + ed07207 commit 2944714

4 files changed

Lines changed: 118 additions & 19 deletions

File tree

boot.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ func main() {
5959
pkglog.Err("Error getting config for %s [%s]", gitReceiveConfAppName, err)
6060
os.Exit(1)
6161
}
62+
cnf.CheckDurations()
63+
6264
if err := gitreceive.Run(cnf); err != nil {
6365
pkglog.Err("running git receive hook [%s]", err)
6466
os.Exit(1)

pkg/gitreceive/build.go

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import (
1010
"os/exec"
1111
"path/filepath"
1212
"strings"
13-
"time"
1413

1514
"github.com/aws/aws-sdk-go/service/s3"
1615
"github.com/deis/builder/pkg"
@@ -21,6 +20,7 @@ import (
2120

2221
"k8s.io/kubernetes/pkg/api"
2322
client "k8s.io/kubernetes/pkg/client/unversioned"
23+
"k8s.io/kubernetes/pkg/util/wait"
2424
)
2525

2626
// repoCmd returns exec.Command(first, others...) with its current working directory repoDir
@@ -168,9 +168,7 @@ func build(conf *Config, s3Client *s3.S3, kubeClient *client.Client, builderKey,
168168
return fmt.Errorf("creating builder pod (%s)", err)
169169
}
170170

171-
timeout := time.Duration(5 * time.Minute)
172-
tick := time.Duration(500 * time.Millisecond)
173-
if err := waitForPod(kubeClient, newPod.Namespace, newPod.Name, tick, timeout); err != nil {
171+
if err := waitForPod(kubeClient, newPod.Namespace, newPod.Name, conf.BuilderPodTickDuration(), conf.BuilderPodWaitDuration()); err != nil {
174172
return fmt.Errorf("watching events for builder pod startup (%s)", err)
175173
}
176174

@@ -192,15 +190,16 @@ func build(conf *Config, s3Client *s3.S3, kubeClient *client.Client, builderKey,
192190
log.Debug("size of logs streamed %v", size)
193191

194192
// poll the s3 server to ensure the slug exists
195-
// TODO: time out looking
196-
for {
193+
err = wait.PollImmediate(conf.ObjectStorageTickDuration(), conf.ObjectStorageWaitDuration(), func() (bool, error) {
197194
exists, err := storage.ObjectExists(s3Client, bucketName, slugBuilderInfo.PushKey())
198195
if err != nil {
199-
return fmt.Errorf("Checking if object %s/%s exists (%s)", bucketName, slugBuilderInfo.PushKey(), err)
200-
}
201-
if exists {
202-
break
196+
return false, fmt.Errorf("Checking if object %s/%s exists (%s)", bucketName, slugBuilderInfo.PushKey(), err)
203197
}
198+
return exists, nil
199+
})
200+
201+
if err != nil {
202+
return fmt.Errorf("Timed out waiting for object in storage. Aborting build...")
204203
}
205204

206205
log.Info("Build complete.")

pkg/gitreceive/config.go

Lines changed: 61 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@ package gitreceive
22

33
import (
44
"strings"
5+
"time"
6+
)
7+
8+
const (
9+
builderPodTick = 100
10+
objectStorageTick = 500
511
)
612

713
type Config struct {
@@ -11,15 +17,19 @@ type Config struct {
1117
RegistryHost string `envconfig:"DEIS_REGISTRY_SERVICE_HOST" required:"true"`
1218
RegistryPort string `envconfig:"DEIS_REGISTRY_SERVICE_PORT" required:"true"`
1319

14-
GitHome string `envconfig:"GIT_HOME" required:"true"`
15-
SSHConnection string `envconfig:"SSH_CONNECTION" required:"true"`
16-
SSHOriginalCommand string `envconfig:"SSH_ORIGINAL_COMMAND" required:"true"`
17-
Repository string `envconfig:"REPOSITORY" required:"true"`
18-
Username string `envconfig:"USERNAME" required:"true"`
19-
Fingerprint string `envconfig:"FINGERPRINT" required:"true"`
20-
PodNamespace string `envconfig:"POD_NAMESPACE" required:"true"`
21-
StorageRegion string `envconfig:"STORAGE_REGION" default:"us-east-1"`
22-
Debug bool `envconfig:"DEBUG" default:"false"`
20+
GitHome string `envconfig:"GIT_HOME" required:"true"`
21+
SSHConnection string `envconfig:"SSH_CONNECTION" required:"true"`
22+
SSHOriginalCommand string `envconfig:"SSH_ORIGINAL_COMMAND" required:"true"`
23+
Repository string `envconfig:"REPOSITORY" required:"true"`
24+
Username string `envconfig:"USERNAME" required:"true"`
25+
Fingerprint string `envconfig:"FINGERPRINT" required:"true"`
26+
PodNamespace string `envconfig:"POD_NAMESPACE" required:"true"`
27+
StorageRegion string `envconfig:"STORAGE_REGION" default:"us-east-1"`
28+
Debug bool `envconfig:"DEBUG" default:"false"`
29+
BuilderPodTickDurationMSec int `envconfig:"BUILDER_POD_TICK_DURATION" default:"100"`
30+
BuilderPodWaitDurationMSec int `envconfig:"BUILDER_POD_WAIT_DURATION" default:"300000"` // 5 minutes
31+
ObjectStorageTickDurationMSec int `envconfing:"OBJECT_STORAGE_TICK_DURATION" default:"500"`
32+
ObjectStorageWaitDurationMSec int `envconfig:"OBJECT_STORAGE_WAIT_DURATION" default:"300000"` // 5 minutes
2333
}
2434

2535
func (c Config) App() string {
@@ -29,3 +39,45 @@ func (c Config) App() string {
2939
}
3040
return c.Repository[0:li]
3141
}
42+
43+
// BuilderPodTickDuration returns the size of the interval used to check for
44+
// the end of the execution of a Pod building an application
45+
func (c Config) BuilderPodTickDuration() time.Duration {
46+
return time.Duration(time.Duration(c.BuilderPodTickDurationMSec) * time.Millisecond)
47+
}
48+
49+
// BuilderPodWaitDuration returns the maximum time to wait for the end
50+
// of the execution of a Pod building an application
51+
func (c Config) BuilderPodWaitDuration() time.Duration {
52+
return time.Duration(time.Duration(c.BuilderPodWaitDurationMSec) * time.Millisecond)
53+
}
54+
55+
// ObjectStorageTickDuration returns the size of the interval used to check for
56+
// the end of an operation that involves the object storage
57+
func (c Config) ObjectStorageTickDuration() time.Duration {
58+
return time.Duration(time.Duration(c.ObjectStorageTickDurationMSec) * time.Millisecond)
59+
}
60+
61+
// ObjectStorageWaitDuration returns the maximum time to wait for the end of an
62+
// operation that involves the object storage
63+
func (c Config) ObjectStorageWaitDuration() time.Duration {
64+
return time.Duration(time.Duration(c.ObjectStorageWaitDurationMSec) * time.Millisecond)
65+
}
66+
67+
// CheckDurations checks if ticks for builder and object storage are not bigger
68+
// than the maximum duration. In case of this it will set the tick to the default
69+
func (c *Config) CheckDurations() {
70+
if c.BuilderPodTickDurationMSec >= c.BuilderPodWaitDurationMSec {
71+
c.BuilderPodTickDurationMSec = builderPodTick
72+
}
73+
if c.BuilderPodTickDurationMSec < builderPodTick {
74+
c.BuilderPodTickDurationMSec = builderPodTick
75+
}
76+
77+
if c.ObjectStorageTickDurationMSec >= c.ObjectStorageWaitDurationMSec {
78+
c.ObjectStorageTickDurationMSec = objectStorageTick
79+
}
80+
if c.ObjectStorageTickDurationMSec < objectStorageTick {
81+
c.ObjectStorageTickDurationMSec = objectStorageTick
82+
}
83+
}

pkg/gitreceive/config_test.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package gitreceive
2+
3+
import (
4+
"testing"
5+
)
6+
7+
type checkCase struct {
8+
podTick int
9+
podWait int
10+
storageTick int
11+
storageWait int
12+
}
13+
14+
func TestCheckDurations(t *testing.T) {
15+
cases := map[checkCase]checkCase{
16+
checkCase{100, 300000, 500, 300000}: checkCase{100, 300000, 500, 300000},
17+
checkCase{0, 300000, 500, 300000}: checkCase{100, 300000, 500, 300000},
18+
checkCase{100, 300000, 0, 300000}: checkCase{100, 300000, 500, 300000},
19+
checkCase{300000, 300000, 500, 300000}: checkCase{100, 300000, 500, 300000},
20+
checkCase{100, 300000, 300000, 300000}: checkCase{100, 300000, 500, 300000},
21+
}
22+
23+
var cnf Config
24+
for tCase, eCase := range cases {
25+
cnf = Config{
26+
BuilderPodTickDurationMSec: tCase.podTick,
27+
BuilderPodWaitDurationMSec: tCase.podWait,
28+
ObjectStorageTickDurationMSec: tCase.storageTick,
29+
ObjectStorageWaitDurationMSec: tCase.storageWait,
30+
}
31+
cnf.CheckDurations()
32+
33+
if cnf.BuilderPodTickDurationMSec != eCase.podTick {
34+
t.Fatalf("expected %v but %v was returned (%v)", eCase.podTick, cnf.BuilderPodTickDurationMSec, tCase)
35+
}
36+
if cnf.BuilderPodWaitDurationMSec != eCase.podWait {
37+
t.Fatalf("expected %v but %v was returned (%v)", eCase.podWait, cnf.BuilderPodWaitDurationMSec, tCase)
38+
}
39+
if cnf.ObjectStorageTickDurationMSec != eCase.storageTick {
40+
t.Fatalf("expected %v but %v was returned (%v)", eCase.storageTick, cnf.ObjectStorageTickDurationMSec, tCase)
41+
}
42+
if cnf.ObjectStorageWaitDurationMSec != eCase.storageWait {
43+
t.Fatalf("expected %v but %v was returned (%v)", eCase.storageWait, cnf.ObjectStorageWaitDurationMSec, tCase)
44+
}
45+
}
46+
}

0 commit comments

Comments
 (0)