Skip to content

Commit

Permalink
Merge pull request #1210 from convox/20160909
Browse files Browse the repository at this point in the history
[RELEASE] 20160909
  • Loading branch information
ddollar authored Sep 10, 2016
2 parents f800997 + fdbbd64 commit ee80998
Show file tree
Hide file tree
Showing 35 changed files with 1,720 additions and 161 deletions.
18 changes: 10 additions & 8 deletions api/awsutil/awsutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ type Request struct {

func (r *Request) String() string {
body := formatBody(strings.NewReader(r.Body))
return fmt.Sprintf("RequestURI: %s\nOperation: %s\nBody: %s", r.RequestURI, r.Operation, body)
return fmt.Sprintf("RequestURI: %q,\nOperation: %q,\nBody: `%s`,", r.RequestURI, r.Operation, body)
}

// Response represents a predefined response.
Expand All @@ -46,24 +46,26 @@ func NewHandler(c []Cycle) *Handler {
}

func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if len(h.cycles) == 0 {
fmt.Println("No cycles remaining to replay.")
w.WriteHeader(404)
return
}

b, err := ioutil.ReadAll(r.Body)
if err != nil {
panic(err)
}

cycle := h.cycles[0]
match := Request{
RequestURI: r.URL.RequestURI(),
Operation: r.Header.Get("X-Amz-Target"),
Body: string(b),
}

if len(h.cycles) == 0 {
fmt.Println("No cycles remaining to replay.")
fmt.Println(match.String())
w.WriteHeader(404)
return
}

cycle := h.cycles[0]

var matched bool

matched = (cycle.Request.Body == "ignore")
Expand Down
39 changes: 36 additions & 3 deletions api/controllers/builds.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ func BuildCreate(rw http.ResponseWriter, r *http.Request) *httperr.Error {
cache := !(r.FormValue("cache") == "false")
manifest := r.FormValue("manifest")
description := r.FormValue("description")
buildImport := (r.FormValue("import") == "true")

repo := r.FormValue("repo")
index := r.FormValue("index")
Expand All @@ -96,7 +97,7 @@ func BuildCreate(rw http.ResponseWriter, r *http.Request) *httperr.Error {
return httperr.Server(err)
}

a, err := models.GetApp(app)
a, err := models.Provider().AppGet(app)
if err != nil {
return httperr.Server(err)
}
Expand All @@ -109,9 +110,15 @@ func BuildCreate(rw http.ResponseWriter, r *http.Request) *httperr.Error {

var b *structs.Build

// if source file was posted, build from tar
if source != nil {
b, err = models.Provider().BuildCreateTar(app, source, r.FormValue("manifest"), r.FormValue("description"), cache)

if buildImport {
b, err = models.Provider().BuildImport(a.Name, source)
} else {
// if source file was posted, build from tar
b, err = models.Provider().BuildCreateTar(app, source, r.FormValue("manifest"), r.FormValue("description"), cache)
}

} else if repo != "" {
b, err = models.Provider().BuildCreateRepo(app, repo, r.FormValue("manifest"), r.FormValue("description"), cache)
} else if index != "" {
Expand Down Expand Up @@ -266,6 +273,32 @@ func BuildCopy(rw http.ResponseWriter, r *http.Request) *httperr.Error {
return RenderJson(rw, b)
}

// BuildExport creates an artifact, representing a build, to be used with another Rack
func BuildExport(rw http.ResponseWriter, r *http.Request) *httperr.Error {
vars := mux.Vars(r)
app := vars["app"]
build := vars["build"]

b, err := models.Provider().BuildGet(app, build)
if awsError(err) == "ValidationError" {
return httperr.Errorf(404, "no such app: %s", app)
}
if err != nil && strings.HasPrefix(err.Error(), "no such build") {
return httperr.Errorf(404, err.Error())
}
if err != nil {
return httperr.Server(err)
}

rw.Header().Set("Content-Type", "application/octet-stream")

if err = models.Provider().BuildExport(app, b.Id, rw); err != nil {
return httperr.Server(err)
}

return nil
}

func BuildLogs(ws *websocket.Conn) *httperr.Error {
vars := mux.Vars(ws.Request())

Expand Down
36 changes: 36 additions & 0 deletions api/controllers/releases.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package controllers

import (
"fmt"
"net/http"
"strings"

"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/convox/rack/api/httperr"
"github.com/convox/rack/api/models"
"github.com/convox/rack/api/structs"
"github.com/gorilla/mux"
)

Expand Down Expand Up @@ -77,3 +79,37 @@ func ReleasePromote(rw http.ResponseWriter, r *http.Request) *httperr.Error {

return RenderJson(rw, rr)
}

// ForkRelease creates a new release based on the app's release
func ForkRelease(app *structs.App) (*structs.Release, error) {
release := structs.NewRelease(app.Name)

if app.Release != "" {
r, err := models.Provider().ReleaseGet(app.Name, app.Release)
if err != nil {
return nil, err
}
id := release.Id
created := release.Created

release = r
release.Id = id
release.Created = created
}

env, err := models.Provider().EnvironmentGet(app.Name)
if err != nil {
fmt.Printf("fn=ForkRelease level=error msg=\"error getting environment: %s\"", err)
}

release.Env = env.Raw()

return &structs.Release{
Id: release.Id,
App: release.App,
Build: release.Build,
Env: release.Env,
Manifest: release.Manifest,
Created: release.Created,
}, nil
}
1 change: 1 addition & 0 deletions api/controllers/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ func NewRouter() (router *mux.Router) {
router.HandleFunc("/apps/{app}", api("app.delete", AppDelete)).Methods("DELETE")
router.HandleFunc("/apps/{app}/builds", api("build.list", BuildList)).Methods("GET")
router.HandleFunc("/apps/{app}/builds", api("build.create", BuildCreate)).Methods("POST")
router.HandleFunc("/apps/{app}/builds/{build}.tgz", api("build.export", BuildExport)).Methods("GET")
router.HandleFunc("/apps/{app}/builds/{build}", api("build.get", BuildGet)).Methods("GET")
router.HandleFunc("/apps/{app}/builds/{build}", api("build.update", BuildUpdate)).Methods("PUT")
router.HandleFunc("/apps/{app}/builds/{build}", api("build.delete", BuildDelete)).Methods("DELETE")
Expand Down
2 changes: 1 addition & 1 deletion api/models/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ func (a *App) ForkRelease() (*Release, error) {
}

release.Id = generateId("R", 10)
release.Created = time.Time{}
release.Created = time.Now()

env, err := Provider().EnvironmentGet(a.Name)
if err != nil {
Expand Down
11 changes: 5 additions & 6 deletions api/models/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/aws/aws-sdk-go/service/ecr"
"github.com/aws/aws-sdk-go/service/ecs"
"github.com/convox/rack/api/structs"
"github.com/fsouza/go-dockerclient"
)

Expand Down Expand Up @@ -147,7 +148,7 @@ func DockerLogout(ac docker.AuthConfiguration) error {

// Log into the appropriate registry for the given app
// This could be the self-hosted v1 registry or an ECR registry
func AppDockerLogin(app App) (string, error) {
func AppDockerLogin(app structs.App) (string, error) {
if registryId := app.Outputs["RegistryId"]; registryId != "" {
return DockerLogin(docker.AuthConfiguration{
Email: "user@convox.com",
Expand Down Expand Up @@ -183,16 +184,15 @@ func PullAppImages() {
}

for _, app := range apps {
a, err := GetApp(app.Name)

a, err := Provider().AppGet(app.Name)
if err != nil {
log.Step("GetApp").Error(err)
continue
}

// retry login a few times in case v1 registry is not yet available
for i := 0; i < maxRetries; i++ {
_, err = AppDockerLogin(app)
_, err = AppDockerLogin(*a)

if err == nil {
break
Expand All @@ -202,8 +202,7 @@ func PullAppImages() {
time.Sleep(30 * time.Second)
}

resources, err := a.Resources()

resources, err := ListResources(a.Name)
if err != nil {
log.Step("Resources").Error(err)
}
Expand Down
103 changes: 98 additions & 5 deletions api/models/fixtures/cron_labels.json
Original file line number Diff line number Diff line change
Expand Up @@ -462,8 +462,33 @@
[
"'use strict';",
"var aws = require('aws-sdk');",
"var ecs = new aws.ECS();",
"var ecs = new aws.ECS({maxRetries:10});",
"var logs = new aws.CloudWatchLogs();",
"var cluster = 'convox-test';",
{
"Fn::Join": [
"",
[
"var logGroup = '",
{
"Ref": "LogGroup"
},
"';"
]
]
},
{
"Fn::Join": [
"",
[
"var release = '",
{
"Ref": "Release"
},
"';"
]
]
},
"var taskDefinitions = {",
{
"Fn::Join": [
Expand Down Expand Up @@ -503,8 +528,31 @@
" ]",
" }",
" };",
" ecs.runTask(params, context.done);",
"};"
" var skew = Math.floor(Math.random()*10000);",
" log(event.process + ':' + release + '/cron skew=' + skew + 'ms command=' + event.command, function(err) {",
" console.log('err2', err);",
" setTimeout(function() { ecs.runTask(params, context.done) }, skew);",
" });",
"};",
"function log(message, cb) {",
" var stream = 'cron-' + (new Date()).getTime();",
" var params = {",
" logGroupName: logGroup,",
" logStreamName: stream",
" }",
" logs.createLogStream(params, function(err) {",
" console.log('err', err);",
" var params = {",
" logEvents: [",
" { message: message, timestamp: (new Date()).getTime() }",
" ],",
" logGroupName: logGroup,",
" logStreamName: stream",
" }",
" console.log(message);",
" logs.putLogEvents(params, cb);",
" })",
"}"
]
]
}
Expand All @@ -518,7 +566,7 @@
]
},
"Runtime": "nodejs",
"Timeout": 10
"Timeout": 50
},
"Type": "AWS::Lambda::Function"
},
Expand Down Expand Up @@ -570,11 +618,56 @@
},
"Effect": "Allow",
"Resource": "*"
},
{
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Effect": "Allow",
"Resource": {
"Fn::Join": [
"",
[
"arn:aws:logs:",
{
"Ref": "AWS::Region"
},
":",
{
"Ref": "AWS::AccountId"
},
":log-group:/aws/lambda/*"
]
]
}
},
{
"Action": [
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Effect": "Allow",
"Resource": {
"Fn::Join": [
"",
[
{
"Fn::GetAtt": [
"LogGroup",
"Arn"
]
},
":*"
]
]
}
}
],
"Version": "2012-10-17"
},
"PolicyName": "Administrator"
"PolicyName": "CronJob"
}
]
},
Expand Down
Loading

0 comments on commit ee80998

Please sign in to comment.