Skip to content

Commit

Permalink
Unified font end and back end, added simple test case
Browse files Browse the repository at this point in the history
  • Loading branch information
jhkolb committed Aug 24, 2016
1 parent 37514e5 commit e611271
Show file tree
Hide file tree
Showing 6 changed files with 198 additions and 40 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ frontend/.idea
frontend/project/*
!frontend/project/*.sbt
frontend/target/*
raptor
110 changes: 110 additions & 0 deletions backend/backend.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package backend

import (
"fmt"
"io/ioutil"
"regexp"
"strconv"

"github.com/golang/protobuf/proto"
"github.com/immesys/spawnpoint/objects"
"github.com/immesys/spawnpoint/spawnclient"
)

func readProtoFile(name string) (*Deployment, error) {
rawBytes, err := ioutil.ReadFile(name)
if err != nil {
return nil, err
}

var deployment Deployment
if err = proto.Unmarshal(rawBytes, &deployment); err != nil {
return nil, err
}
return &deployment, nil
}

func paramStringToSlice(params *map[string]string, name string) []string {
paramVal, ok := (*params)[name]
if ok {
return regexp.MustCompile(",\\s*").Split(paramVal, -1)
}
return nil
}

func lenientBoolParse(s string) bool {
b, err := strconv.ParseBool(s)
if err != nil {
return false
}
return b
}

func DeployConfig(configFile string) ([]chan *objects.SPLogMsg, error) {
deployment, err := readProtoFile(configFile)
if err != nil {
return nil, err
}
spawnClient, err := spawnclient.New("127.0.0.1:28589", deployment.Entity)
if err != nil {
err = fmt.Errorf("Failed to initialize spawn client: %v", err)
return nil, err
}

allSpawnpoints := make(map[string]objects.SpawnPoint)
for _, uri := range deployment.SpawnpointUris {
spawnpoints, err := spawnClient.Scan(uri)
if err == nil {
for _, spawnpoint := range spawnpoints {
allSpawnpoints[spawnpoint.Alias] = spawnpoint
}
}
}

// Ensure that all service configs reference a valid spawnpoint -- no partial deployments
for _, service := range deployment.Services {
if _, ok := allSpawnpoints[service.SpawnpointName]; !ok {
err = fmt.Errorf("Service %s references unknown spawnpoint %s", service.Name, service.SpawnpointName)
return nil, err
}
}

var logs []chan *objects.SPLogMsg
for _, service := range deployment.Services {
build := paramStringToSlice(&service.Params, "build")
run := paramStringToSlice(&service.Params, "run")
volumes := paramStringToSlice(&service.Params, "volumes")
includedDirs := paramStringToSlice(&service.Params, "includedDirs")
includedFiles := paramStringToSlice(&service.Params, "includedFiles")
cpuShares, err := strconv.ParseUint(service.Params["cpuShares"], 10, 64)
if err != nil {
return nil, err
}

config := objects.SvcConfig{
ServiceName: service.Name,
Entity: service.Params["entity"],
Container: service.ImageName,
Build: build,
Source: service.Params["source"],
AptRequires: service.Params["aptRequires"],
Run: run,
MemAlloc: service.Params["memAlloc"],
CPUShares: cpuShares,
Volumes: volumes,
IncludedFiles: includedFiles,
IncludedDirs: includedDirs,
AutoRestart: lenientBoolParse(service.Params["autoRestart"]),
RestartInt: service.Params["restartInt"],
}

relevantSp := allSpawnpoints[service.SpawnpointName]
log, err := spawnClient.DeployService(&config, relevantSp.URI, service.Name)
if err != nil {
return nil, err
}

logs = append(logs, log)
}
return logs, nil
}
37 changes: 0 additions & 37 deletions backend/main.go

This file was deleted.

2 changes: 1 addition & 1 deletion backend/raptor.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ object ConfigParser extends JavaTokenParsers {

def memAllocLiteral: Parser[String] = """[0-9]+[MmGg]""".r

def containerName: Parser[String] = path ~ opt(":" ~ ident) ^^ {
case containerPath ~ None => containerPath
case containerPath ~ Some(":" ~ tag) => containerPath + ":" + tag
}

// The right-hand side of any parameter
def value: Parser[String] = stringLiteral ^^ (stripQuotes(_)) |
URI |
Expand All @@ -26,7 +31,7 @@ object ConfigParser extends JavaTokenParsers {
wholeNumber |
floatingPointNumber

def valueSequence: Parser[String] = "[" ~> repsep(value, ",") <~ opt(",") ~ "]" ^^ ("[" + _.mkString(", ") + "]")
def valueSequence: Parser[String] = "[" ~> repsep(value, ",") <~ opt(",") ~ "]" ^^ (_.mkString(", "))

def parameter: Parser[(String, String)] = ident ~ (":" | "=") ~ (value | ident | valueSequence) ^^ { case k ~ (":" | "=") ~ v => (k, v) }

Expand All @@ -47,7 +52,7 @@ object ConfigParser extends JavaTokenParsers {
"on" ~> (ident | stringLiteral ^^ (stripQuotes(_))) ^^ (Left(_)) |
"where" ~> parameterSequence ^^ (Right(_))

def serviceDeployment: Parser[Service] = "container" ~ path ~ "as" ~ ident ~ "with" ~ parameterSequence ~ spawnpointSpec ^^
def serviceDeployment: Parser[Service] = "container" ~ containerName ~ "as" ~ ident ~ "with" ~ parameterSequence ~ spawnpointSpec ^^
{ case "container" ~ imgName ~ "as" ~ svcName ~ "with" ~ params ~ spec =>
spec match {
case Left(spawnpointName) => Service(svcName, imgName, params, spawnpointName, Map.empty[String, String])
Expand Down
79 changes: 79 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package main

import (
"fmt"
"os"
"os/exec"
"strings"
"time"

"github.com/codegangsta/cli"
"github.com/immesys/spawnpoint/objects"
"github.com/jhkolb/raptor/backend"
"github.com/mgutz/ansi"
)

const parserLocation = "frontend/target/scala-2.11/raptor-frontend-assembly-0.1.jar"
const tempOutputFile = "temp.protobuf"

func main() {
app := cli.NewApp()
app.Name = "raptor"
app.Usage = "Configuration manager for Spawnpoint deployments"
app.Version = "0.0.1 'Aviary'"

app.Commands = []cli.Command{
{
Name: "submit",
Usage: "Submit a deployment configuration file",
Action: actionSubmit,
Flags: []cli.Flag{
cli.StringFlag{
Name: "input, i",
Usage: "set the input configuration file",
Value: "",
},
},
},
}

app.Run(os.Args)
}

func actionSubmit(c *cli.Context) error {
inputFile := c.String("input")
if inputFile == "" {
fmt.Println("Missing 'input' parameter")
os.Exit(1)
}

cmd := exec.Command("scala", parserLocation, inputFile, tempOutputFile)
if err := cmd.Run(); err != nil {
fmt.Println("Failed to parse config file")
os.Exit(1)
}

logs, err := backend.DeployConfig(tempOutputFile)
os.Remove(tempOutputFile)
if err != nil {
fmt.Printf("%sDeployment failed: %v%s\n", ansi.ColorCode("red+b"), err, ansi.ColorCode("reset"))
os.Exit(1)
}

fmt.Printf("%sDeployment complete, tailing logs. Ctrl-C to quit.%s\n",
ansi.ColorCode("green+b"), ansi.ColorCode("reset"))
for _, log := range logs {
go tailLog(log)
}
for {
time.Sleep(5 * time.Second)
}
}

func tailLog(log chan *objects.SPLogMsg) {
for logMsg := range log {
tstring := time.Unix(0, logMsg.Time).Format("01/02 15:04:05")
fmt.Printf("[%s] %s%s::%s > %s%s\n", tstring, ansi.ColorCode("blue+b"), logMsg.SPAlias,
logMsg.Service, ansi.ColorCode("reset"), strings.Trim(logMsg.Contents, "\n"))
}
}

0 comments on commit e611271

Please sign in to comment.