Skip to content

Commit

Permalink
Merge pull request #1012 from convox/20160809
Browse files Browse the repository at this point in the history
[RELEASE] 20160809
  • Loading branch information
ddollar authored Aug 10, 2016
2 parents 93fc19b + 5147814 commit 8068bdc
Show file tree
Hide file tree
Showing 11 changed files with 240 additions and 18 deletions.
2 changes: 1 addition & 1 deletion api/models/templates.go

Large diffs are not rendered by default.

22 changes: 10 additions & 12 deletions api/models/templates/app.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -382,18 +382,16 @@
"Condition": "Enabled{{ upper .ProcessName }}",
"DependsOn": [ "{{ .ResourceName }}SecurityGroup" ],
"Properties": {
"Scheme": { "Fn::If": [ "Internal",
"internal",
{{ if eq .Scheme "internal" }}
"internal"
{{ else }}
{ "Ref": "AWS::NoValue" }
{{ end }}
] },
"Subnets": { "Fn::If": [ "Private",
{ "Ref": "SubnetsPrivate" },
{ "Ref": "Subnets" }
] },
{{ if eq .Scheme "internal" }}
"Scheme": "internal",
"Subnets": { "Fn::If": [ "Private",
{ "Ref": "SubnetsPrivate" },
{ "Ref": "Subnets" }
] },
{{ else }}
"Scheme": { "Fn::If": [ "Internal", "internal", { "Ref": "AWS::NoValue" } ] },
"Subnets": { "Fn::If": [ "Internal", { "Ref": "SubnetsPrivate" }, { "Ref": "Subnets" } ] },
{{ end }}
"ConnectionDrainingPolicy": { "Enabled": true, "Timeout": 60 },
"ConnectionSettings": { "IdleTimeout": "{{ .IdleTimeout }}" },
"CrossZone": true,
Expand Down
12 changes: 10 additions & 2 deletions manifest/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,18 @@ func (m *Manifest) Build(dir, appName string, s Stream, cache bool) error {

for image, tag := range pulls {
args := []string{"pull"}

output, err := DefaultRunner.CombinedOutput(Docker("images", "-q", image))
if err != nil {
return err
}

args = append(args, image)

if err := DefaultRunner.Run(s, Docker("pull", image)); err != nil {
return fmt.Errorf("build error: %s", err)
if !cache || len(output) == 0 {
if err := DefaultRunner.Run(s, Docker("pull", image)); err != nil {
return fmt.Errorf("build error: %s", err)
}
}

if err := DefaultRunner.Run(s, Docker("tag", image, tag)); err != nil {
Expand Down
91 changes: 88 additions & 3 deletions manifest/build_test.go
Original file line number Diff line number Diff line change
@@ -1,23 +1,39 @@
package manifest_test

import (
"math"
"os/exec"
"testing"

"github.com/convox/rack/manifest"
"github.com/stretchr/testify/assert"
)

type ExecResponse struct {
Output []byte
Error error
}

type TestExecer struct {
Commands []*exec.Cmd
CannedResponses []ExecResponse
Index int
Commands []*exec.Cmd
}

func NewTestExecer() *TestExecer {
return &TestExecer{
Commands: make([]*exec.Cmd, 0),
CannedResponses: []ExecResponse{},
Commands: make([]*exec.Cmd, 0),
}
}

func (p *TestExecer) CombinedOutput(cmd *exec.Cmd) ([]byte, error) {
i := int(math.Mod(float64(p.Index), float64(len(p.CannedResponses))))
resp := p.CannedResponses[i]
p.Index++
return resp.Output, resp.Error
}

func (p *TestExecer) Run(s manifest.Stream, cmd *exec.Cmd) error {
p.Commands = append(p.Commands, cmd)
return nil
Expand All @@ -28,11 +44,80 @@ func (p *TestExecer) RunAsync(s manifest.Stream, cmd *exec.Cmd, done chan error)
done <- nil
}

func TestBuild(t *testing.T) {
func TestBuildWithCache(t *testing.T) {
output := manifest.NewOutput()
str := output.Stream("build")
dr := manifest.DefaultRunner
te := NewTestExecer()
te.CannedResponses = []ExecResponse{
ExecResponse{
Output: []byte("dockerid"),
Error: nil,
},
}

manifest.DefaultRunner = te
defer func() { manifest.DefaultRunner = dr }()

m, err := manifestFixture("full-v1")
if err != nil {
t.Error(err)
}

err = m.Build(".", "web", str, true)

cmd1 := []string{"docker", "build", "-f", "./Dockerfile.dev", "-t", "web/web", "."}
cmd2 := []string{"docker", "tag", "convox/postgres", "web/database"}

assert.Equal(t, len(te.Commands), 2)
assert.Equal(t, te.Commands[0].Args, cmd1)
assert.Equal(t, te.Commands[1].Args, cmd2)
}

func TestBuildCacheNoImage(t *testing.T) {
output := manifest.NewOutput()
str := output.Stream("build")
dr := manifest.DefaultRunner
te := NewTestExecer()
te.CannedResponses = []ExecResponse{
ExecResponse{
Output: []byte(""),
Error: nil,
},
}

manifest.DefaultRunner = te
defer func() { manifest.DefaultRunner = dr }()

m, err := manifestFixture("full-v1")
if err != nil {
t.Error(err)
}

err = m.Build(".", "web", str, true)

cmd1 := []string{"docker", "build", "-f", "./Dockerfile.dev", "-t", "web/web", "."}
cmd2 := []string{"docker", "pull", "convox/postgres"}
cmd3 := []string{"docker", "tag", "convox/postgres", "web/database"}

assert.Equal(t, len(te.Commands), 3)
assert.Equal(t, te.Commands[0].Args, cmd1)
assert.Equal(t, te.Commands[1].Args, cmd2)
assert.Equal(t, te.Commands[2].Args, cmd3)
}

func TestBuildNoCache(t *testing.T) {
output := manifest.NewOutput()
str := output.Stream("build")
dr := manifest.DefaultRunner
te := NewTestExecer()
te.CannedResponses = []ExecResponse{
ExecResponse{
Output: []byte("dockeid"),
Error: nil,
},
}

manifest.DefaultRunner = te
defer func() { manifest.DefaultRunner = dr }()

Expand Down
9 changes: 9 additions & 0 deletions manifest/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
)

type Runner interface {
CombinedOutput(cmd *exec.Cmd) ([]byte, error)
Run(s Stream, cmd *exec.Cmd) error
RunAsync(s Stream, cmd *exec.Cmd, dobe chan error)
}
Expand All @@ -17,14 +18,22 @@ type Exec struct{}

var DefaultRunner Runner = new(Exec)

//Run synchronously calls the command and pipes the output to the stream,
func (e *Exec) Run(s Stream, cmd *exec.Cmd) error {
return run(s, cmd)
}

//RunAsync synchronously calls the command and pipes the output to the stream,
func (e *Exec) RunAsync(s Stream, cmd *exec.Cmd, done chan error) {
runAsync(s, cmd, done)
}

//CombinedOutput synchronously calls the command and returns the output,
//useful for internal checks
func (e *Exec) CombinedOutput(cmd *exec.Cmd) ([]byte, error) {
return cmd.CombinedOutput()
}

func run(s Stream, cmd *exec.Cmd) error {
done := make(chan error, 1)
runAsync(s, cmd, done)
Expand Down
11 changes: 11 additions & 0 deletions manifest/fixtures/invalid-cron.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
version: "2"
services:
web:
build: .
command: bin/web
dockerfile: Dockerfile.dev
entrypoint: /sbin/init
labels:
- convox.cron.my_job=0 * * * ? bin/myjob
- convox.baz=4

12 changes: 12 additions & 0 deletions manifest/fixtures/invalid-health-timeout.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
version: "2"
services:
web:
build: .
command: bin/web
dockerfile: Dockerfile.dev
entrypoint: /sbin/init
labels:
- convox.health.timeout=61
- convox.baz=4


19 changes: 19 additions & 0 deletions manifest/fixtures/invalid-link-no-ports.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
version: "2"
services:
web:
build: .
command: bin/web
dockerfile: Dockerfile.dev
entrypoint: /sbin/init
links:
- database
ports:
- 80:5000
- 443:5001
privileged: true
volumes:
- /var/db
database:
image: convox/postgres


20 changes: 20 additions & 0 deletions manifest/fixtures/invalid-link.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
version: "2"
services:
web:
build: .
command: bin/web
dockerfile: Dockerfile.dev
entrypoint: /sbin/init
links:
- database2
ports:
- 80:5000
- 443:5001
privileged: true
volumes:
- /var/db
database:
image: convox/postgres
ports:
- 5432

38 changes: 38 additions & 0 deletions manifest/manifest.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"net"
"regexp"
"sort"
"strconv"
"strings"
"time"

Expand Down Expand Up @@ -86,6 +87,43 @@ func (m Manifest) Validate() error {
)
}
}

labels = entry.LabelsByPrefix("convox.health.timeout")
for _, v := range labels {
i, err := strconv.Atoi(v)
if err != nil {
return fmt.Errorf(
"convox.health.timeout is invalid for %s, must be a number between 0 and 60",
entry.Name,
)
}

if i < 0 || i > 60 {
return fmt.Errorf(
"convox.health.timeout is invalid for %s, must be a number between 0 and 60",
entry.Name,
)
}
}

for _, l := range entry.Links {
ls, ok := m.Services[l]
if !ok {
return fmt.Errorf(
"%s links to service: %s which does not exist",
entry.Name,
l,
)
}

if len(ls.Ports) == 0 {
return fmt.Errorf(
"%s links to service: %s which does not expose any ports",
entry.Name,
l,
)
}
}
}
return nil
}
Expand Down
22 changes: 22 additions & 0 deletions manifest/manifest_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,28 @@ func TestManifestMarshalYaml(t *testing.T) {
assert.Equal(t, m2.Services["food"].Command.Array, arrayCmd.Array)
}

func TestManifestValidate(t *testing.T) {
_, cerr := manifestFixture("invalid-cron")
if assert.NotNil(t, cerr) {
assert.Equal(t, cerr.Error(), "Cron task my_job is not valid (cron names can contain only alphanumeric characters and dashes and must be between 4 and 30 characters)")
}

_, lerr := manifestFixture("invalid-link")
if assert.NotNil(t, lerr) {
assert.Equal(t, lerr.Error(), "web links to service: database2 which does not exist")
}

_, lperr := manifestFixture("invalid-link-no-ports")
if assert.NotNil(t, lperr) {
assert.Equal(t, lperr.Error(), "web links to service: database which does not expose any ports")
}

_, herr := manifestFixture("invalid-health-timeout")
if assert.NotNil(t, herr) {
assert.Equal(t, herr.Error(), "convox.health.timeout is invalid for web, must be a number between 0 and 60")
}
}

func manifestFixture(name string) (*manifest.Manifest, error) {
return manifest.LoadFile(fmt.Sprintf("fixtures/%s.yml", name))
}

0 comments on commit 8068bdc

Please sign in to comment.