Skip to content

Commit a35fa93

Browse files
sitolejakubno
andauthored
Fix panic when build not found because concurrent access (#1103)
Co-authored-by: Jakub Novak <[email protected]>
1 parent 27e26d4 commit a35fa93

File tree

18 files changed

+389
-321
lines changed

18 files changed

+389
-321
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ generate-tests/%:
230230

231231
.PHONY: migrate
232232
migrate:
233-
$(MAKE) -C packages/db migrate/up
233+
$(MAKE) -C packages/db migrate
234234

235235
.PHONY: switch-env
236236
switch-env:

packages/api/internal/api/spec.gen.go

Lines changed: 100 additions & 100 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/api/internal/api/types.gen.go

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/api/internal/cache/templates/cache.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,15 +96,14 @@ func (c *TemplateCache) Get(ctx context.Context, aliasOrEnvID string, teamID uui
9696

9797
build = &result.EnvBuild
9898
template := result.Env
99-
aliases := result.Aliases
10099

101100
cluster := uuid.Nil
102101
if template.ClusterID != nil {
103102
cluster = *template.ClusterID
104103
}
105104

106105
c.aliasCache.cache.Set(template.ID, template.ID, templateInfoExpiration)
107-
for _, alias := range aliases {
106+
for _, alias := range result.Aliases {
108107
c.aliasCache.cache.Set(alias, template.ID, templateInfoExpiration)
109108
}
110109

@@ -122,7 +121,7 @@ func (c *TemplateCache) Get(ctx context.Context, aliasOrEnvID string, teamID uui
122121
TemplateID: template.ID,
123122
BuildID: build.ID.String(),
124123
Public: template.Public,
125-
Aliases: &aliases,
124+
Aliases: result.Aliases,
126125
},
127126
teamID: teamID,
128127
clusterID: clusterID,

packages/api/internal/handlers/sandbox_create.go

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,7 @@ func (a *APIStore) PostSandboxes(c *gin.Context) {
9494
telemetry.ReportEvent(ctx, "Checked team access")
9595

9696
c.Set("envID", env.TemplateID)
97-
if aliases := env.Aliases; aliases != nil {
98-
setTemplateNameMetric(c, *aliases)
99-
}
97+
setTemplateNameMetric(c, env.Aliases)
10098

10199
sandboxID := InstanceIDPrefix + id.Generate()
102100

@@ -232,12 +230,9 @@ func setTemplateNameMetric(c *gin.Context, aliases []string) {
232230
c.Set(metricTemplateAlias, "other")
233231
}
234232

235-
func firstAlias(aliases *[]string) string {
236-
if aliases == nil {
237-
return ""
238-
}
239-
if len(*aliases) == 0 {
233+
func firstAlias(aliases []string) string {
234+
if len(aliases) == 0 {
240235
return ""
241236
}
242-
return (*aliases)[0]
237+
return aliases[0]
243238
}

packages/api/internal/handlers/template_request_build.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ type TemplateBuildResponse struct {
4545
TemplateID string
4646
BuildID string
4747
Public bool
48-
Aliases *[]string
48+
Aliases []string
4949
KernelVersion string
5050
FirecrackerVersion string
5151
StartCmd *string
@@ -362,7 +362,7 @@ func (a *APIStore) BuildTemplate(ctx context.Context, req BuildTemplateRequest)
362362
TemplateID: *build.EnvID,
363363
BuildID: build.ID.String(),
364364
Public: public,
365-
Aliases: &aliases,
365+
Aliases: aliases,
366366
KernelVersion: build.KernelVersion,
367367
FirecrackerVersion: build.FirecrackerVersion,
368368
StartCmd: build.StartCmd,

packages/api/internal/handlers/templates_list.go

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@ import (
66
"github.com/gin-gonic/gin"
77
"github.com/google/uuid"
88
"go.opentelemetry.io/otel/attribute"
9+
"go.uber.org/zap"
910

1011
"github.com/e2b-dev/infra/packages/api/internal/api"
1112
"github.com/e2b-dev/infra/packages/api/internal/auth"
1213
"github.com/e2b-dev/infra/packages/db/queries"
14+
"github.com/e2b-dev/infra/packages/shared/pkg/logger"
1315
"github.com/e2b-dev/infra/packages/shared/pkg/telemetry"
1416
)
1517

@@ -75,12 +77,10 @@ func (a *APIStore) GetTemplates(c *gin.Context, params api.GetTemplatesParams) {
7577
telemetry.WithTeamID(team.ID.String()),
7678
)
7779

78-
envs, err := a.db.GetEnvs(ctx, team.ID)
80+
envs, err := a.sqlcDB.GetTeamTemplates(ctx, team.ID)
7981
if err != nil {
80-
a.sendAPIStoreError(c, http.StatusInternalServerError, "Error when getting sandbox templates")
81-
82-
telemetry.ReportCriticalError(ctx, "error when getting envs", err)
83-
82+
a.sendAPIStoreError(c, http.StatusInternalServerError, "Error when getting templates")
83+
telemetry.ReportCriticalError(ctx, "error when getting templates", err)
8484
return
8585
}
8686

@@ -93,28 +93,40 @@ func (a *APIStore) GetTemplates(c *gin.Context, params api.GetTemplatesParams) {
9393
templates := make([]*api.Template, 0, len(envs))
9494
for _, item := range envs {
9595
var createdBy *api.TeamUser
96-
if item.CreatedBy != nil {
96+
if item.CreatorEmail != nil && item.CreatorID != nil {
9797
createdBy = &api.TeamUser{
98-
Id: item.CreatedBy.Id,
99-
Email: item.CreatedBy.Email,
98+
Id: *item.CreatorID,
99+
Email: *item.CreatorEmail,
100100
}
101101
}
102102

103+
envdVersion := ""
104+
if item.BuildEnvdVersion != nil {
105+
envdVersion = *item.BuildEnvdVersion
106+
} else {
107+
zap.L().Error("failed to determine envd version", logger.WithTemplateID(item.Env.ID))
108+
}
109+
110+
diskMB := int64(0)
111+
if item.BuildTotalDiskSizeMb != nil {
112+
diskMB = *item.BuildTotalDiskSizeMb
113+
}
114+
103115
templates = append(templates, &api.Template{
104-
TemplateID: item.TemplateID,
105-
BuildID: item.BuildID,
106-
CpuCount: int32(item.VCPU),
107-
MemoryMB: int32(item.RAMMB),
108-
DiskSizeMB: int32(item.DiskMB),
109-
Public: item.Public,
116+
TemplateID: item.Env.ID,
117+
BuildID: item.BuildID.String(),
118+
CpuCount: int32(item.BuildVcpu),
119+
MemoryMB: int32(item.BuildRamMb),
120+
DiskSizeMB: int32(diskMB),
121+
Public: item.Env.Public,
110122
Aliases: item.Aliases,
111-
CreatedAt: item.CreatedAt,
112-
UpdatedAt: item.UpdatedAt,
113-
LastSpawnedAt: item.LastSpawnedAt,
114-
SpawnCount: item.SpawnCount,
115-
BuildCount: item.BuildCount,
123+
CreatedAt: item.Env.CreatedAt,
124+
UpdatedAt: item.Env.UpdatedAt,
125+
LastSpawnedAt: item.Env.LastSpawnedAt,
126+
SpawnCount: item.Env.SpawnCount,
127+
BuildCount: item.Env.BuildCount,
116128
CreatedBy: createdBy,
117-
EnvdVersion: item.EnvdVersion,
129+
EnvdVersion: envdVersion,
118130
})
119131
}
120132

packages/db/Makefile

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,14 @@ goose := GOOSE_DBSTRING=$(POSTGRES_CONNECTION_STRING) go tool goose -table "_mig
55
IMAGE := e2b-orchestration/db-migrator
66

77
.PHONY: migrate
8-
migrate:migrate/up
9-
migrate:migrate/down
10-
migrate/%:
8+
migrate:
119
@echo "Applying Postgres migration *$(notdir $@)*"
12-
@$(goose) $(notdir $@)
10+
@$(goose) up
11+
@echo "Done"
12+
migrate/up: migrate
13+
migrate/down:
14+
@echo "Reverting Postgres migration *$(notdir $@)*"
15+
@$(goose) down
1316
@echo "Done"
1417

1518
.PHONY: build-debug

packages/db/migrations/20000101000000_auth.sql

Lines changed: 11 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -2,62 +2,22 @@
22
-- +goose StatementBegin
33
CREATE SCHEMA IF NOT EXISTS auth;
44

5-
-- Create RLS policies for user management
6-
DO $$
7-
BEGIN
8-
BEGIN
9-
IF NOT EXISTS (
10-
SELECT 1
11-
FROM pg_roles
12-
WHERE rolname = 'authenticated'
13-
) THEN
14-
EXECUTE 'CREATE ROLE authenticated;';
15-
END IF;
16-
END;
17-
END $$;
18-
;
19-
20-
-- Create RLS policies for user management
21-
DO $$
22-
BEGIN
23-
IF NOT EXISTS (
24-
SELECT 1
25-
FROM pg_proc p
26-
JOIN pg_namespace n ON p.pronamespace = n.oid
27-
WHERE p.proname = 'uid' AND n.nspname = 'auth'
28-
) THEN
29-
EXECUTE 'CREATE FUNCTION auth.uid() RETURNS uuid AS $func$
30-
BEGIN
31-
RETURN gen_random_uuid();
32-
END;
33-
$func$ LANGUAGE plpgsql;';
34-
END IF;
35-
END;
36-
$$;
5+
CREATE ROLE authenticated;
376

7+
CREATE FUNCTION auth.uid() RETURNS uuid AS $func$
8+
BEGIN
9+
RETURN gen_random_uuid();
10+
END;
11+
$func$ LANGUAGE plpgsql;
3812

3913
-- Grant execute on auth.uid() to postgres role
4014
GRANT EXECUTE ON FUNCTION auth.uid() TO postgres;
4115

42-
-- Check if the table exists before trying to create it
43-
DO $$
44-
BEGIN
45-
IF NOT EXISTS (
46-
SELECT 1
47-
FROM information_schema.tables
48-
WHERE table_schema = 'auth'
49-
AND table_name = 'users'
50-
) THEN
51-
EXECUTE '
52-
CREATE TABLE auth.users (
53-
id uuid NOT NULL DEFAULT gen_random_uuid(),
54-
email text NOT NULL,
55-
PRIMARY KEY (id)
56-
);';
57-
END IF;
58-
END;
59-
$$;
60-
16+
CREATE TABLE auth.users (
17+
id uuid NOT NULL DEFAULT gen_random_uuid(),
18+
email text NOT NULL,
19+
PRIMARY KEY (id)
20+
);
6121
-- +goose StatementEnd
6222

6323
-- +goose Down
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
-- name: GetTeamTemplates :many
2+
SELECT sqlc.embed(e),
3+
eb.id as build_id, eb.vcpu as build_vcpu, eb.ram_mb as build_ram_mb, eb.total_disk_size_mb as build_total_disk_size_mb, eb.envd_version as build_envd_version, eb.firecracker_version as build_firecracker_version,
4+
u.id as creator_id, u.email as creator_email,
5+
COALESCE(ea.aliases, ARRAY[]::text[])::text[] AS aliases
6+
FROM public.envs AS e
7+
LEFT JOIN auth.users AS u ON u.id = e.created_by
8+
LEFT JOIN LATERAL (
9+
SELECT ARRAY_AGG(alias ORDER BY alias) AS aliases
10+
FROM public.env_aliases
11+
WHERE env_id = e.id
12+
) ea ON TRUE
13+
LEFT JOIN LATERAL (
14+
SELECT b.*
15+
FROM public.env_builds AS b
16+
WHERE b.env_id = e.id AND b.status = 'uploaded'
17+
ORDER BY b.finished_at DESC
18+
LIMIT 1
19+
) eb ON TRUE
20+
WHERE
21+
e.team_id = $1
22+
AND eb.id IS NOT NULL
23+
AND NOT EXISTS (
24+
SELECT 1
25+
FROM public.snapshots AS s
26+
WHERE s.env_id = e.id
27+
)
28+
ORDER BY e.created_at ASC;

0 commit comments

Comments
 (0)