Skip to content

Commit

Permalink
Cleaned up repo + added README
Browse files Browse the repository at this point in the history
  • Loading branch information
erwinvaneyk committed Mar 27, 2019
1 parent 55f9645 commit beab41c
Show file tree
Hide file tree
Showing 8 changed files with 90 additions and 48 deletions.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ COPY . .
# Future: Speed up builds by also copying the mod cache ($GOPATH/pkg/mod)

ENV GO111MODULE=on
RUN go get
WORKDIR /go/src/github.com/erwinvaneyk/simfaas/cmd/simfission
RUN go get
RUN CGO_ENABLED=0 go build \
-gcflags=-trimpath="/go/src/github.com/erwinvaneyk/simfaas" \
-asmflags=-trimpath="/go/src/github.com/erwinvaneyk/simfaas" \
Expand Down
1 change: 0 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
REPO=docker.io/erwinvaneyk
IMAGE=simfission
VERSION=latest
ROOT_DIR=$(dirname $0)

.PHONY: publish test build install

Expand Down
22 changes: 21 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,21 @@
# simfaas
# SimFaaS

SimFaaS is aimed to be a generic FaaS emulator/simulator (though currently it
is just an emulator). The goal is to be able to evaluate key metrics, such as
runtime, cold start duration and resource cost, in FaaS platforms.

## Building

See Makefile.

## Fission

SimFaaS includes a specific implementation for Fission called: **SimFission**.
SimFission is a wrapper on top of simfaas that emulates a part of the
API of Fission.

It currently emulates the following part of the (web) API:
1. Resolving a function name to a service.
2. Tapping of a service.
3. Executing a fission function.
4. Getting info for a given function.
6 changes: 3 additions & 3 deletions cmd/simfission/simfission.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,8 @@ import (
"time"
)

// simfaas - is a very simple mock of a FaaS platform to implement the sleep function with minimal interference

var (
// buildTime is a UNIX datetime that should be injected at build time.
buildTime string // UNIX

//
Expand Down Expand Up @@ -82,7 +81,7 @@ func main() {
// Parse arguments
coldStart := flag.Duration("cold-start", 0, "The default cold start duration")
keepWarm := flag.Duration("keep-warm", 0, "How long the function should be kept warm after an execution.")
addr := flag.String("addr", ":8888", "Address to bind the server to.")
addr := flag.String("addr", ":8888", "Address serve the API on.")
flag.Parse()
log.Printf("simfission %s", buildTime)

Expand All @@ -108,6 +107,7 @@ func main() {
if err := fission.Start(); err != nil {
log.Fatalf("Failed to start FaaS simulator: %v", err)
}
defer fission.Close()

// Publish FaaS simulator resource usage to Prometheus
go func() {
Expand Down
66 changes: 44 additions & 22 deletions fission.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,28 @@ import (
`time`
)

// Fission is a wrapper on top of simfaas that emulates a part of the
// interface of Fission.
type Fission struct {
Platform *Platform
FnFactory func(name string) *FunctionConfig

// CreateUndefinedFunctions enables, if set to true,
// the automatic creation of a function if it is called.
CreateUndefinedFunctions bool
}

func (f *Fission) Start() error {
return f.Platform.Start()
}

func (f *Fission) Close() error {
return f.Platform.Close()
}

// GetServiceForFunction emulates the mapping of a function to a service
// name/host. Currently it just returns the name of the function as the
// service name.
func (f *Fission) GetServiceForFunction(fnName string) (string, error) {
f.createIfUndefined(fnName)
fn, ok := f.Platform.Get(fnName)
Expand All @@ -28,7 +44,10 @@ func (f *Fission) GetServiceForFunction(fnName string) (string, error) {
return fn.name, nil
}

// We assume that url is just the function name
// TapService deploys (or keeps deployed) a function instance for the function.
//
// Note: similar as in GetServiceForFunction, we assume that the service url is
// just the function name.
func (f *Fission) TapService(svcURL string) error {
if len(svcURL) == 0 {
return errors.New("no url provided to tap")
Expand All @@ -48,6 +67,15 @@ func (f *Fission) TapService(svcURL string) error {
return nil
}

// Run emulates the execution of a Fission Function.
//
// If the runtime is not nil it will be used to override the runtime
// specified in the config of the function.
func (f *Fission) Run(fnName string, runtime *time.Duration) (*ExecutionReport, error) {
f.createIfUndefined(fnName)
return f.Platform.Run(fnName, runtime)
}

func (f *Fission) Serve() http.Handler {
handler := &RegexpHandler{}
handler.HandleFunc(regexp.MustCompile("/v2/functions/.*"), f.HandleFunctionsGet)
Expand All @@ -57,7 +85,8 @@ func (f *Fission) Serve() http.Handler {
return handler
}

// /v2/getServiceForFunction
// HandleGetServiceForFunction emulates the /v2/getServiceForFunction
// Fission endpoint.
func (f *Fission) HandleGetServiceForFunction(w http.ResponseWriter, r *http.Request) {
bs, err := ioutil.ReadAll(r.Body)
r.Body.Close()
Expand All @@ -81,11 +110,7 @@ func (f *Fission) HandleGetServiceForFunction(w http.ResponseWriter, r *http.Req
w.Write([]byte(svc))
}

func (f *Fission) Start() error {
return f.Platform.Start()
}

// /v2/tapService
// HandleTapService emulates the /v2/tapService Fission endpoint.
func (f *Fission) HandleTapService(w http.ResponseWriter, r *http.Request) {
bs, err := ioutil.ReadAll(r.Body)
defer r.Body.Close()
Expand All @@ -105,19 +130,22 @@ func (f *Fission) HandleTapService(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
}

// /v2/functions/.*
// HandleFunctionsGet emulates the /v2/functions/.* Fission endpoints.
// Currently it simply returns an empty map.
func (f *Fission) HandleFunctionsGet(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("{}"))
}

// /fission-function/
// HandleFunctionRun emulates the /fission-function/.* Fission endpoints.
//
// It checks for the presence of the runtime query parameter,
// which allows you to override the runtime of the function.
func (f *Fission) HandleFunctionRun(w http.ResponseWriter, r *http.Request) {
// Parse arguments: fnname, runtime
var seconds float64
var err error
if queryRuntime := r.URL.Query().Get("runtime"); len(queryRuntime) > 0 {
// Read query
seconds, err = strconv.ParseFloat(queryRuntime, 64)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
Expand All @@ -126,22 +154,18 @@ func (f *Fission) HandleFunctionRun(w http.ResponseWriter, r *http.Request) {
}
runtime := time.Duration(seconds * float64(time.Second))
fnName := getFunctionNameFromUrl(r.URL)
f.createIfUndefined(fnName)

// Run function
report, err := f.Platform.Run(fnName, &runtime)
report, err := f.Run(fnName, &runtime)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}

// Simulate runtime
result, _ := json.Marshal(map[string]interface{}{
"started_at": report.StartedAt.UnixNano(),
"finished_at": report.FinishedAt.UnixNano(),
"coldStart": report.ColdStart.Nanoseconds(),
"runtime": report.Runtime.Nanoseconds(),
})
result, err := json.Marshal(report)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusOK)
w.Write(result)
}
Expand All @@ -162,8 +186,6 @@ type ObjectMeta struct {
// Namespace string `json:"namespace,omitempty" protobuf:"bytes,3,opt,name=namespace"`
}

var fnUrlRegEx = regexp.MustCompile("/(.*)$")

func getFunctionNameFromUrl(url *url.URL) string {
return url.Path[strings.LastIndex(url.Path, "/")+1:]
}
Expand Down
8 changes: 5 additions & 3 deletions fission_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import (
`testing`
)

func TestFission_Run(t *testing.T) {
simFission := NewFission(0, 0)
func TestFission_Setup(t *testing.T) {
simFission := Fission{
Platform: New(),
}
srv := httptest.NewServer(simFission.Serve())
defer srv.Close()
srv.Close()
}
16 changes: 7 additions & 9 deletions httputil.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,8 @@ import (
`regexp`
)

//
// To enable wildcards
//

type route struct {
pattern *regexp.Regexp
handler http.Handler
}

// RegexpHandler is simple http.Handler to enable the use of
// wildcards in routes.
type RegexpHandler struct {
routes []*route
}
Expand All @@ -38,3 +31,8 @@ func (h *RegexpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// no pattern matched; send 404 response
http.NotFound(w, r)
}

type route struct {
pattern *regexp.Regexp
handler http.Handler
}
17 changes: 9 additions & 8 deletions simfaas.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ type FunctionConfig struct {
}

type ExecutionReport struct {
ColdStart time.Duration
Runtime time.Duration
StartedAt time.Time
FinishedAt time.Time
ColdStart time.Duration `json:"cold_start"`
Runtime time.Duration `json:"runtime"`
StartedAt time.Time `json:"started_at"`
FinishedAt time.Time `json:"finished_at"`
}

type Function struct {
Expand All @@ -47,8 +47,8 @@ type Function struct {
// active reports the number of executions of this function currently running.
active atomic.Uint32

// queued reports the number of executions of this function currently queued, waiting for instances to free up or
// additional to be deployed.
// queued reports the number of executions of this function currently queued,
// waiting for instances to free up or additional to be deployed.
queued atomic.Uint32
}

Expand Down Expand Up @@ -136,9 +136,10 @@ func (p *Platform) cleanup(fn *Function) {
fn.instances.Store(0)
}

// Run emulates a function execution in a synchronous way, sleeping for the entire executionRuntime
// Run emulates a function execution in a synchronous way,
// sleeping for the entire executionRuntime.
//
// TODO handle inputs and outputs
// TODO emulate inputs and outputs
func (p *Platform) Run(fnName string, executionRuntime *time.Duration) (*ExecutionReport, error) {
startedAt := time.Now()
// Find the function
Expand Down

0 comments on commit beab41c

Please sign in to comment.