// BuildSave creates or updates a build item in DynamoDB. It takes an optional // bucket argument, which if set indicates to PUT Log data into S3 func (p *AWSProvider) BuildSave(b *structs.Build) error { a, err := p.AppGet(b.App) if err != nil { return err } if b.Id == "" { return fmt.Errorf("Id can not be blank") } if b.Started.IsZero() { b.Started = time.Now() } req := &dynamodb.PutItemInput{ Item: map[string]*dynamodb.AttributeValue{ "id": &dynamodb.AttributeValue{S: aws.String(b.Id)}, "app": &dynamodb.AttributeValue{S: aws.String(b.App)}, "status": &dynamodb.AttributeValue{S: aws.String(b.Status)}, "created": &dynamodb.AttributeValue{S: aws.String(b.Started.Format(SortableTime))}, }, TableName: aws.String(buildsTable(b.App)), } if b.Description != "" { req.Item["description"] = &dynamodb.AttributeValue{S: aws.String(b.Description)} } if b.Manifest != "" { req.Item["manifest"] = &dynamodb.AttributeValue{S: aws.String(b.Manifest)} } if b.Release != "" { req.Item["release"] = &dynamodb.AttributeValue{S: aws.String(b.Release)} } if !b.Ended.IsZero() { req.Item["ended"] = &dynamodb.AttributeValue{S: aws.String(b.Ended.Format(SortableTime))} } if b.Logs != "" { _, err := p.s3().PutObject(&s3.PutObjectInput{ Body: bytes.NewReader([]byte(b.Logs)), Bucket: aws.String(a.Outputs["Settings"]), ContentLength: aws.Int64(int64(len(b.Logs))), Key: aws.String(fmt.Sprintf("builds/%s.log", b.Id)), }) if err != nil { return err } } _, err = p.dynamodb().PutItem(req) return err }
func (p *AWSProvider) buildWait(a *structs.App, b *structs.Build, cmd *exec.Cmd, stdout io.ReadCloser) { // scan all output out := "" scanner := bufio.NewScanner(stdout) for scanner.Scan() { text := scanner.Text() out += text + "\n" p.kinesis().PutRecord(&kinesis.PutRecordInput{ Data: []byte(text), PartitionKey: aws.String(string(time.Now().UnixNano())), StreamName: aws.String(a.Outputs["Kinesis"]), }) } if err := scanner.Err(); err != nil { helpers.Error(nil, err) // send internal error to rollbar } // and wait for a return code werr := cmd.Wait() // reload build item to get data from BuildUpdate callback b, err := p.BuildGet(b.App, b.Id) if err != nil { helpers.Error(nil, err) // send internal error to rollbar return } // Wait / return code are errors, consider the build failed if werr != nil { b.Status = "failed" } // save final build logs / status b.Logs = string(out) err = p.BuildSave(b) if err != nil { helpers.Error(nil, err) // send internal error to rollbar return } }
func (p *AWSProvider) BuildRelease(b *structs.Build) (*structs.Release, error) { releases, err := p.ReleaseList(b.App) if err != nil { return nil, err } r := structs.NewRelease(b.App) newId := r.Id if len(releases) > 0 { r = &releases[0] } r.Id = newId r.Created = time.Time{} r.Build = b.Id r.Manifest = b.Manifest a, err := p.AppGet(b.App) if err != nil { return r, err } err = p.ReleaseSave(r, a.Outputs["Settings"], a.Parameters["Key"]) if err != nil { return r, err } b.Release = r.Id err = p.BuildSave(b) if err == nil { p.EventSend(&structs.Event{ Action: "release:create", Data: map[string]string{ "app": r.App, "id": r.Id, }, }, nil) } return r, err }
// BuildSave creates or updates a build item in DynamoDB. It takes an optional // bucket argument, which if set indicates to PUT Log data into S3 func (p *AWSProvider) BuildSave(b *structs.Build) error { _, err := p.AppGet(b.App) if err != nil { return err } if b.Id == "" { return fmt.Errorf("Id can not be blank") } if b.Started.IsZero() { b.Started = time.Now() } if p.IsTest() { b.Started = time.Unix(1473028693, 0).UTC() b.Ended = time.Unix(1473028892, 0).UTC() } req := &dynamodb.PutItemInput{ Item: map[string]*dynamodb.AttributeValue{ "id": {S: aws.String(b.Id)}, "app": {S: aws.String(b.App)}, "status": {S: aws.String(b.Status)}, "created": {S: aws.String(b.Started.Format(sortableTime))}, }, TableName: aws.String(p.DynamoBuilds), } if b.Description != "" { req.Item["description"] = &dynamodb.AttributeValue{S: aws.String(b.Description)} } if b.Manifest != "" { req.Item["manifest"] = &dynamodb.AttributeValue{S: aws.String(b.Manifest)} } if b.Logs != "" { req.Item["logs"] = &dynamodb.AttributeValue{S: aws.String(b.Logs)} } if b.Reason != "" { req.Item["reason"] = &dynamodb.AttributeValue{S: aws.String(b.Reason)} } if b.Release != "" { req.Item["release"] = &dynamodb.AttributeValue{S: aws.String(b.Release)} } if !b.Ended.IsZero() { req.Item["ended"] = &dynamodb.AttributeValue{S: aws.String(b.Ended.Format(sortableTime))} } if len(b.Tags) > 0 { tags, err := json.Marshal(b.Tags) if err != nil { return err } req.Item["tags"] = &dynamodb.AttributeValue{B: tags} } _, err = p.dynamodb().PutItem(req) return err }
func (p *AWSProvider) buildWait(a *structs.App, b *structs.Build, cmd *exec.Cmd, stdout io.ReadCloser) { // scan all output scanner := bufio.NewScanner(stdout) out := "" for scanner.Scan() { text := scanner.Text() out += text + "\n" } if err := scanner.Err(); err != nil { helpers.Error(nil, err) // send internal error to rollbar } var cmdStatus string waitErr := make(chan error) timeout := time.After(1 * time.Hour) go func() { err := cmd.Wait() switch err.(type) { case *exec.ExitError: waitErr <- err default: waitErr <- nil } }() select { case werr := <-waitErr: // Wait / return code are errors, consider the build failed if werr != nil { cmdStatus = "failed" } case <-timeout: cmdStatus = "timeout" // Force kill the build container since its taking way to long killCmd := exec.Command("docker", "kill", fmt.Sprintf("build-%s", b.Id)) killCmd.Start() } // reload build item to get data from BuildUpdate callback b, err := p.BuildGet(b.App, b.Id) if err != nil { helpers.Error(nil, err) // send internal error to rollbar return } if cmdStatus != "" { // Careful not to override the status set by BuildUpdate b.Status = cmdStatus } // save final build logs / status b.Logs = out err = p.BuildSave(b) if err != nil { helpers.Error(nil, err) // send internal error to rollbar return } }