Skip to content

Commit

Permalink
refactor out dependency container
Browse files Browse the repository at this point in the history
  • Loading branch information
zekroTJA committed May 23, 2024
1 parent 6e5cdba commit 5bcd86d
Show file tree
Hide file tree
Showing 25 changed files with 286 additions and 257 deletions.
175 changes: 74 additions & 101 deletions cmd/ranna/main.go
Original file line number Diff line number Diff line change
@@ -1,6 1,7 @@
package main

import (
"fmt"
"os"
"os/signal"
"strings"
Expand All @@ -15,99 16,40 @@ import (
"github.com/ranna-go/ranna/internal/sandbox/docker"
"github.com/ranna-go/ranna/internal/scheduler"
"github.com/ranna-go/ranna/internal/spec"
"github.com/ranna-go/ranna/internal/static"
"github.com/sarulabs/di/v2"
"github.com/sirupsen/logrus"
)

func main() {
godotenv.Load()

diBuilder, _ := di.NewBuilder()

diBuilder.Add(di.Def{
Name: static.DiConfigProvider,
Build: func(ctn di.Container) (interface{}, error) {
p := config.NewPaerser("")
return p, p.Load()
},
})

diBuilder.Add(di.Def{
Name: static.DiSpecProvider,
Build: func(ctn di.Container) (interface{}, error) {
cfg := ctn.Get(static.DiConfigProvider).(config.Provider)
specFile := cfg.Config().SpecFile
var p spec.Provider
if strings.HasPrefix(specFile, "https://") || strings.HasPrefix(specFile, "http://") {
p = spec.NewHttpProvider(specFile)
} else {
p = spec.NewFileProvider(specFile)
}
return p, p.Load()
},
})

diBuilder.Add(di.Def{
Name: static.DiSandboxProvider,
Build: func(ctn di.Container) (interface{}, error) {
return docker.NewDockerSandboxProvider(ctn)
},
})
type ConfigProvider interface {
Config() *config.Config
}

diBuilder.Add(di.Def{
Name: static.DiSandboxManager,
Build: func(ctn di.Container) (interface{}, error) {
return sandbox.NewManager(ctn)
},
Close: func(obj interface{}) error {
logrus.Info("cleaning up running sandboxes ...")
m := obj.(sandbox.Manager)
m.Cleanup()
return nil
},
})
type Scheduler interface {
Schedule(spec interface{}, job func()) (id interface{}, err error)
}

diBuilder.Add(di.Def{
Name: static.DiFileProvider,
Build: func(ctn di.Container) (v interface{}, err error) {
v = file.NewLocalFileProvider()
return
},
})
type Manager interface {
PrepareEnvironments(force bool) []error
}

diBuilder.Add(di.Def{
Name: static.DiAPI,
Build: func(ctn di.Container) (interface{}, error) {
return api.NewRestAPI(ctn)
},
})
type SpecProvider interface {
Spec() *spec.SafeSpecMap
Load() error
}

diBuilder.Add(di.Def{
Name: static.DiNamespaceProvider,
Build: func(ctn di.Container) (v interface{}, err error) {
v = namespace.NewRandomProvider()
return
},
})
func checkErr(err error) {
if err != nil {
fmt.Fprintf(os.Stderr, "initialization failed: %v\n", err)
os.Exit(1)
}
}

diBuilder.Add(di.Def{
Name: static.DiScheduler,
Build: func(ctn di.Container) (interface{}, error) {
sched := scheduler.NewCronScheduler()
sched.Start()
return sched, nil
},
Close: func(obj interface{}) error {
sched := obj.(scheduler.Scheduler)
sched.Stop()
return nil
},
})
func main() {
godotenv.Load()

ctn := diBuilder.Build()
cfg := config.NewPaerser("")
err := cfg.Load()
checkErr(err)

cfg := ctn.Get(static.DiConfigProvider).(config.Provider)
logrus.SetLevel(logrus.Level(cfg.Config().Log.Level))
logrus.SetFormatter(&logrus.TextFormatter{
ForceColors: cfg.Config().Debug,
Expand All @@ -117,35 59,66 @@ func main() {
logrus.Warn("ATTENTION: Sandbox Networking is enabled by config! This is a high security risk!")
}

specFile := cfg.Config().SpecFile
var specProvider SpecProvider
if strings.HasPrefix(specFile, "https://") || strings.HasPrefix(specFile, "http://") {
specProvider = spec.NewHttpProvider(specFile)
} else {
specProvider = spec.NewFileProvider(specFile)
}
err = specProvider.Load()
checkErr(err)

sandboxProvider, err := docker.NewProvider(cfg)
checkErr(err)

fileProvider := file.NewLocalFileProvider()

namespaceProvider := namespace.NewRandomProvider()

sandboxManager, err := sandbox.NewManager(sandboxProvider, specProvider, fileProvider, cfg, namespaceProvider)
checkErr(err)
defer func() {
logrus.Info("cleaning up running sandboxes ...")
// TODO: Handle errors
sandboxManager.Cleanup()
}()

webApi, err := api.NewRestAPI(cfg, specProvider, sandboxManager)
checkErr(err)

schedulerProvider := scheduler.NewCronScheduler()
schedulerProvider.Start()
defer schedulerProvider.Stop()

if !cfg.Config().SkipStartupPrep {
mgr := ctn.Get(static.DiSandboxManager).(sandbox.Manager)
logrus.Info("Prepare spec environments ...")
mgr.PrepareEnvironments(true)
// TODO: Handle errors
sandboxManager.PrepareEnvironments(true)
} else {
logrus.Warn("Skipping spec preparation on startup")
}

if err := scheduleTasks(ctn); err != nil {
if err := scheduleTasks(cfg, schedulerProvider, sandboxManager, specProvider); err != nil {
logrus.WithError(err).Fatal("failed scheduling job")
}

api := ctn.Get(static.DiAPI).(api.API)
go api.ListenAndServeBlocking()
go func() {
err = webApi.ListenAndServeBlocking()
checkErr(err)
}()

sc := make(chan os.Signal, 1)
signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt, os.Kill)
<-sc

// Tear down dependency instances
ctn.DeleteWithSubContainers()
}

func scheduleTasks(ctn di.Container) (err error) {
cfg := ctn.Get(static.DiConfigProvider).(config.Provider)
sched := ctn.Get(static.DiScheduler).(scheduler.Scheduler)
mgr := ctn.Get(static.DiSandboxManager).(sandbox.Manager)
specProvider := ctn.Get(static.DiSpecProvider).(spec.Provider)

func scheduleTasks(
cfg ConfigProvider,
sched Scheduler,
mgr Manager,
specProvider SpecProvider,
) (err error) {
schedule := func(name, spec string, job func()) (err error) {
if spec != "" {
logrus.WithField("name", name).WithField("spec", spec).Info("Scheduling job")
Expand All @@ -154,17 127,17 @@ func scheduleTasks(ctn di.Container) (err error) {
return
}

spec := cfg.Config().Scheduler.UpdateImages
if err = schedule("update spec environments", spec, func() {
scheduleSpec := cfg.Config().Scheduler.UpdateImages
if err = schedule("update spec environments", scheduleSpec, func() {
logrus.Info("Updating spec environments ...")
defer logrus.Info("Updating spec finished")
mgr.PrepareEnvironments(true)
}); err != nil {
return
}

spec = cfg.Config().Scheduler.UpdateSpecs
if err = schedule("update specs", spec, func() {
scheduleSpec = cfg.Config().Scheduler.UpdateSpecs
if err = schedule("update specs", scheduleSpec, func() {
if err = specProvider.Load(); err != nil {
logrus.WithError(err).Error("Failed loading specs")
} else {
Expand Down
28 changes: 28 additions & 0 deletions internal/api/interfaces.go
Original file line number Diff line number Diff line change
@@ -1 1,29 @@
package api

import (
"github.com/ranna-go/ranna/internal/config"
"github.com/ranna-go/ranna/internal/sandbox"
"github.com/ranna-go/ranna/internal/spec"
"github.com/ranna-go/ranna/pkg/models"
)

type ConfigProvider interface {
Config() *config.Config
}

type SpecProvider interface {
Spec() *spec.SafeSpecMap
}

type SandboxManager interface {
RunInSandbox(
req *models.ExecutionRequest,
cSpn chan string,
cOut, cErr chan []byte,
cClose chan bool,
) (err error)
PrepareEnvironments(force bool) []error
KillAndCleanUp(id string) (bool, error)
Cleanup() []error
GetProvider() sandbox.Provider
}
12 changes: 5 additions & 7 deletions internal/api/restapi.go
Original file line number Diff line number Diff line change
@@ -1,14 1,12 @@
package api

import (
"errors"
"strings"

"github.com/gofiber/fiber/v2"
v1 "github.com/ranna-go/ranna/internal/api/v1"
"github.com/ranna-go/ranna/internal/config"
"github.com/ranna-go/ranna/internal/static"
"github.com/ranna-go/ranna/pkg/models"
"github.com/sarulabs/di/v2"
"github.com/sirupsen/logrus"
)

Expand All @@ -17,8 15,7 @@ type RestAPI struct {
app *fiber.App
}

func NewRestAPI(ctn di.Container) (r *RestAPI, err error) {
cfg := ctn.Get(static.DiConfigProvider).(config.Provider)
func NewRestAPI(cfg ConfigProvider, spec SpecProvider, manager SandboxManager) (r *RestAPI, err error) {

r = &RestAPI{
bindAddress: cfg.Config().API.BindAddress,
Expand All @@ -37,7 34,7 @@ func NewRestAPI(ctn di.Container) (r *RestAPI, err error) {
ProxyHeader: "X-Forwarded-For",
})

new(v1.Router).Setup(r.app.Group("/v1"), ctn)
new(v1.Router).Setup(r.app.Group("/v1"), cfg, spec, manager)

return
}
Expand All @@ -48,7 45,8 @@ func (r *RestAPI) ListenAndServeBlocking() error {
}

func errorHandler(ctx *fiber.Ctx, err error) error {
if fErr, ok := err.(*fiber.Error); ok {
var fErr *fiber.Error
if errors.As(err, &fErr) {
ctx.Status(fErr.Code)
return ctx.JSON(&models.ErrorModel{
Error: fErr.Message,
Expand Down
28 changes: 28 additions & 0 deletions internal/api/v1/interfaces.go
Original file line number Diff line number Diff line change
@@ -1 1,29 @@
package v1

import (
"github.com/ranna-go/ranna/internal/config"
"github.com/ranna-go/ranna/internal/sandbox"
"github.com/ranna-go/ranna/internal/spec"
"github.com/ranna-go/ranna/pkg/models"
)

type SpecProvider interface {
Spec() *spec.SafeSpecMap
}

type ConfigProvider interface {
Config() *config.Config
}

type SandboxManager interface {
RunInSandbox(
req *models.ExecutionRequest,
cSpn chan string,
cOut, cErr chan []byte,
cClose chan bool,
) (err error)
PrepareEnvironments(force bool) []error
KillAndCleanUp(id string) (bool, error)
Cleanup() []error
GetProvider() sandbox.Provider
}
Loading

0 comments on commit 5bcd86d

Please sign in to comment.