Skip to content

Abstract the storage to allow for local storage in tests and developmnet #458

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/actions/build-sandbox-template/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ runs:
GCP_DOCKER_REPOSITORY_NAME: "custom-environments-tests"
# Not used, but required to be defined
GOOGLE_SERVICE_ACCOUNT_BASE64: "required-but-not-needed"
TEMPLATE_STORAGE: "local"
run: |
echo "TESTS_SANDBOX_TEMPLATE_ID=${TEMPLATE_ID}" >> .env.test
echo "TESTS_SANDBOX_BUILD_ID=${BUILD_ID}" >> .env.test
Expand Down
2 changes: 2 additions & 0 deletions .github/actions/start-services/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,11 @@ runs:
env:
ENVD_TIMEOUT: "60s"
SUPABASE_JWT_SECRETS: "supabasejwtsecretsupabasejwtsecret"
TEMPLATE_STORAGE: "local"
run: |
echo "ENVD_TIMEOUT=${ENVD_TIMEOUT}" >> .env.test
echo "SUPABASE_JWT_SECRETS=${SUPABASE_JWT_SECRETS}" >> .env.test
echo "TEMPLATE_STORAGE=${TEMPLATE_STORAGE}" >> .env.test

mkdir -p ~/logs

Expand Down
3 changes: 2 additions & 1 deletion packages/orchestrator/cmd/simulate-headers-merge/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ import (
"log"
"os"

"github.com/google/uuid"

"github.com/e2b-dev/infra/packages/shared/pkg/storage"
"github.com/e2b-dev/infra/packages/shared/pkg/storage/gcs"
"github.com/e2b-dev/infra/packages/shared/pkg/storage/header"
"github.com/google/uuid"
)

func main() {
Expand Down
34 changes: 31 additions & 3 deletions packages/shared/pkg/storage/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ package storage

import (
"fmt"
"os"
"path/filepath"

"github.com/e2b-dev/infra/packages/shared/pkg/storage/header"
)

const (
EnvsDisk = "/mnt/disks/fc-envs/v1"
EnvsDisk = "/mnt/disks/fc-envs/v1"
LocalStorageDir = "/tmp"

KernelsDir = "/fc-kernels"
KernelMountDir = "/fc-vm"
Expand Down Expand Up @@ -37,13 +39,21 @@ const (
// Path to the directory where the kernel can be accessed inside when the dirs are mounted.
var KernelMountedPath = filepath.Join(KernelMountDir, KernelName)

type Type string

const (
LocalStorage Type = "local"
BucketStorage Type = "bucket"
)

type TemplateFiles struct {
TemplateId string
BuildId string
KernelVersion string
FirecrackerVersion string

hugePages bool
hugePages bool
StorageType Type
}

func NewTemplateFiles(
Expand All @@ -53,12 +63,22 @@ func NewTemplateFiles(
firecrackerVersion string,
hugePages bool,
) *TemplateFiles {
// Choose where are the template build data stored. Default to bucket storage.
var storageType Type
switch os.Getenv("TEMPLATE_STORAGE") {
case "local":
storageType = LocalStorage
default:
storageType = BucketStorage
}

return &TemplateFiles{
TemplateId: templateId,
BuildId: buildId,
KernelVersion: kernelVersion,
FirecrackerVersion: firecrackerVersion,
hugePages: hugePages,
StorageType: storageType,
}
}

Expand Down Expand Up @@ -112,7 +132,15 @@ func (t *TemplateFiles) StorageSnapfilePath() string {
}

func (t *TemplateFiles) BuildDir() string {
return filepath.Join(EnvsDisk, t.TemplateId, buildDirName, t.BuildId)
var baseDir string
switch t.StorageType {
case LocalStorage:
baseDir = LocalStorageDir
default:
baseDir = EnvsDisk
}

return filepath.Join(baseDir, t.TemplateId, buildDirName, t.BuildId)
}

func (t *TemplateFiles) BuildMemfilePath() string {
Expand Down
31 changes: 31 additions & 0 deletions packages/shared/pkg/storage/template_bucket.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package storage

import (
"context"

"github.com/e2b-dev/infra/packages/shared/pkg/storage/gcs"
"github.com/e2b-dev/infra/packages/shared/pkg/storage/header"
)

type TemplateBuild interface {
Remove(ctx context.Context) error
Upload(ctx context.Context, snapfilePath string, memfilePath *string, rootfsPath *string) chan error
}

func NewTemplateBuild(
memfileHeader *header.Header,
rootfsHeader *header.Header,
files *TemplateFiles,
) TemplateBuild {
switch files.StorageType {
case LocalStorage:
return &TemplateLocalBuild{files: files}
default:
return &TemplateBucketBuild{
bucket: gcs.GetTemplateBucket(),
memfileHeader: memfileHeader,
rootfsHeader: rootfsHeader,
files: files,
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
"github.com/e2b-dev/infra/packages/shared/pkg/storage/header"
)

type TemplateBuild struct {
type TemplateBucketBuild struct {
files *TemplateFiles

memfileHeader *header.Header
Expand All @@ -21,20 +21,7 @@ type TemplateBuild struct {
bucket *gcs.BucketHandle
}

func NewTemplateBuild(
memfileHeader *header.Header,
rootfsHeader *header.Header,
files *TemplateFiles,
) *TemplateBuild {
return &TemplateBuild{
bucket: gcs.GetTemplateBucket(),
memfileHeader: memfileHeader,
rootfsHeader: rootfsHeader,
files: files,
}
}

func (t *TemplateBuild) Remove(ctx context.Context) error {
func (t *TemplateBucketBuild) Remove(ctx context.Context) error {
err := gcs.RemoveDir(ctx, t.bucket, t.files.StorageDir())
if err != nil {
return fmt.Errorf("error when removing template build '%s': %w", t.files.StorageDir(), err)
Expand All @@ -43,7 +30,7 @@ func (t *TemplateBuild) Remove(ctx context.Context) error {
return nil
}

func (t *TemplateBuild) uploadMemfileHeader(ctx context.Context, h *header.Header) error {
func (t *TemplateBucketBuild) uploadMemfileHeader(ctx context.Context, h *header.Header) error {
object := gcs.NewObject(ctx, t.bucket, t.files.StorageMemfileHeaderPath())

serialized, err := header.Serialize(h.Metadata, h.Mapping)
Expand All @@ -59,7 +46,7 @@ func (t *TemplateBuild) uploadMemfileHeader(ctx context.Context, h *header.Heade
return nil
}

func (t *TemplateBuild) uploadMemfile(ctx context.Context, memfilePath string) error {
func (t *TemplateBucketBuild) uploadMemfile(ctx context.Context, memfilePath string) error {
object := gcs.NewObject(ctx, t.bucket, t.files.StorageMemfilePath())

err := object.UploadWithCli(ctx, memfilePath)
Expand All @@ -70,7 +57,7 @@ func (t *TemplateBuild) uploadMemfile(ctx context.Context, memfilePath string) e
return nil
}

func (t *TemplateBuild) uploadRootfsHeader(ctx context.Context, h *header.Header) error {
func (t *TemplateBucketBuild) uploadRootfsHeader(ctx context.Context, h *header.Header) error {
object := gcs.NewObject(ctx, t.bucket, t.files.StorageRootfsHeaderPath())

serialized, err := header.Serialize(h.Metadata, h.Mapping)
Expand All @@ -86,7 +73,7 @@ func (t *TemplateBuild) uploadRootfsHeader(ctx context.Context, h *header.Header
return nil
}

func (t *TemplateBuild) uploadRootfs(ctx context.Context, rootfsPath string) error {
func (t *TemplateBucketBuild) uploadRootfs(ctx context.Context, rootfsPath string) error {
object := gcs.NewObject(ctx, t.bucket, t.files.StorageRootfsPath())

err := object.UploadWithCli(ctx, rootfsPath)
Expand All @@ -98,7 +85,7 @@ func (t *TemplateBuild) uploadRootfs(ctx context.Context, rootfsPath string) err
}

// Snapfile is small enough so we dont use composite upload.
func (t *TemplateBuild) uploadSnapfile(ctx context.Context, snapfile io.Reader) error {
func (t *TemplateBucketBuild) uploadSnapfile(ctx context.Context, snapfile io.Reader) error {
object := gcs.NewObject(ctx, t.bucket, t.files.StorageSnapfilePath())

n, err := object.ReadFrom(snapfile)
Expand All @@ -109,7 +96,7 @@ func (t *TemplateBuild) uploadSnapfile(ctx context.Context, snapfile io.Reader)
return nil
}

func (t *TemplateBuild) Upload(
func (t *TemplateBucketBuild) Upload(
ctx context.Context,
snapfilePath string,
memfilePath *string,
Expand Down
24 changes: 24 additions & 0 deletions packages/shared/pkg/storage/template_build_local.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package storage

import (
"context"
)

type TemplateLocalBuild struct {
files *TemplateFiles
}

func (t *TemplateLocalBuild) Remove(ctx context.Context) error {
return nil
}

func (t *TemplateLocalBuild) Upload(
ctx context.Context,
snapfilePath string,
memfilePath *string,
rootfsPath *string,
) chan error {
chanErr := make(chan error, 1)
close(chanErr)
return chanErr
}
5 changes: 1 addition & 4 deletions packages/template-manager/cmd/build-template/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import (

"github.com/e2b-dev/infra/packages/shared/pkg/storage"
"github.com/e2b-dev/infra/packages/template-manager/internal/build"
"github.com/e2b-dev/infra/packages/template-manager/internal/template"
)

func main() {
Expand Down Expand Up @@ -72,9 +71,7 @@ func Build(ctx context.Context, kernelVersion, fcVersion, templateID, buildID st
return fmt.Errorf("error building template: %w", err)
}

tempStorage := template.NewStorage(ctx)

buildStorage := tempStorage.NewBuild(t.TemplateFiles)
buildStorage := storage.NewTemplateBuild(nil, nil, t.TemplateFiles)

memfilePath := t.BuildMemfilePath()
rootfsPath := t.BuildRootfsPath()
Expand Down
49 changes: 24 additions & 25 deletions packages/template-manager/internal/build/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,24 @@ package build
import (
"context"
"fmt"
"os"
"os/exec"
"strings"
"time"

"github.com/bits-and-blooms/bitset"
"github.com/docker/docker/client"
docker "github.com/fsouza/go-dockerclient"
"github.com/google/uuid"
"go.opentelemetry.io/otel/trace"

template_manager "github.com/e2b-dev/infra/packages/shared/pkg/grpc/template-manager"
"github.com/e2b-dev/infra/packages/shared/pkg/storage"
"github.com/e2b-dev/infra/packages/shared/pkg/storage/header"
"github.com/e2b-dev/infra/packages/shared/pkg/telemetry"
"github.com/e2b-dev/infra/packages/template-manager/internal/cache"
"github.com/e2b-dev/infra/packages/template-manager/internal/template"
docker "github.com/fsouza/go-dockerclient"
"github.com/google/uuid"
"go.opentelemetry.io/otel/trace"
"os"

"go.uber.org/zap"
"os/exec"
"strings"
"time"
)

type TemplateBuilder struct {
Expand All @@ -30,20 +31,18 @@ type TemplateBuilder struct {
buildLogger *zap.Logger
dockerClient *client.Client
legacyDockerClient *docker.Client
templateStorage *template.Storage
}

const cleanupTimeout = time.Second * 10

func NewBuilder(logger *zap.Logger, buildLogger *zap.Logger, tracer trace.Tracer, dockerClient *client.Client, legacyDockerClient *docker.Client, templateStorage *template.Storage, buildCache *cache.BuildCache) *TemplateBuilder {
func NewBuilder(logger *zap.Logger, buildLogger *zap.Logger, tracer trace.Tracer, dockerClient *client.Client, legacyDockerClient *docker.Client, buildCache *cache.BuildCache) *TemplateBuilder {
return &TemplateBuilder{
logger: logger,
tracer: tracer,
buildCache: buildCache,
buildLogger: buildLogger,
dockerClient: dockerClient,
legacyDockerClient: legacyDockerClient,
templateStorage: templateStorage,
}
}

Expand Down Expand Up @@ -86,20 +85,6 @@ func (b *TemplateBuilder) Build(ctx context.Context, template *Env, envID string
return err
}

// Remove build files if build fails or times out
defer func() {
if err != nil {
removeCtx, cancel := context.WithTimeout(context.Background(), cleanupTimeout)
defer cancel()

removeErr := b.templateStorage.Remove(removeCtx, buildID)
if removeErr != nil {
b.logger.Error("Error while removing build files", zap.Error(removeErr))
telemetry.ReportError(ctx, removeErr)
}
}
}()

// MEMFILE
memfilePath := template.BuildMemfilePath()
memfileDiffPath := template.BuildMemfileDiffPath()
Expand Down Expand Up @@ -221,6 +206,20 @@ func (b *TemplateBuilder) Build(ctx context.Context, template *Env, envID string
template.TemplateFiles,
)

// Remove build files if build fails or times out
defer func() {
if err != nil {
removeCtx, cancel := context.WithTimeout(context.Background(), cleanupTimeout)
defer cancel()

removeErr := templateBuild.Remove(removeCtx)
if removeErr != nil {
b.logger.Error("Error while removing build files", zap.Error(removeErr))
telemetry.ReportError(ctx, removeErr)
}
}
}()

upload := templateBuild.Upload(
ctx,
template.BuildSnapfilePath(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package server
import (
"context"
"fmt"

"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"
"go.uber.org/zap"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func (s *ServerStore) TemplateBuildDelete(ctx context.Context, in *template_mana
s.wg.Add(1)
defer s.wg.Done()

err := template.Delete(childCtx, s.tracer, s.artifactRegistry, s.templateStorage, in.BuildID)
err := template.Delete(childCtx, s.tracer, s.artifactRegistry, s.templateBuild, in.BuildID)
if err != nil {
return nil, err
}
Expand Down
Loading
Loading