Skip to content

Commit 34c005a

Browse files
author
root
committed
remove docker local mode
1 parent eb709e3 commit 34c005a

61 files changed

Lines changed: 738 additions & 949 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Makefile

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -245,11 +245,6 @@ endif
245245

246246
redo:
247247
@echo "Full rebuild: building artifacts and image before replacing container + volumes..."
248-
@if grep -q '^APPOS_SECRET_KEY=replace-with-a-random-base64-secret' build/.env 2>/dev/null; then \
249-
NEW_KEY=$$(openssl rand -base64 32); \
250-
sed -i "s|^APPOS_SECRET_KEY=replace-with-a-random-base64-secret|APPOS_SECRET_KEY=$$NEW_KEY|" build/.env; \
251-
echo "✓ Generated APPOS_SECRET_KEY in build/.env"; \
252-
fi
253248
@$(MAKE) build
254249
@$(MAKE) image build-local
255250
@docker rm -f $$(docker ps -aq --filter name=$(CONTAINER)) 2>/dev/null || true
@@ -266,6 +261,7 @@ run:
266261
@docker cp backend/appos $(CONTAINER):/usr/local/bin/appos
267262
@docker cp web/dist/. $(CONTAINER):/usr/share/nginx/html/web/
268263
@docker cp templates/apps/. $(CONTAINER):/appos/data/templates/apps/
264+
@docker cp build/supervisord.conf $(CONTAINER):/etc/supervisor/supervisord.conf
269265
@docker cp build/nginx.conf $(CONTAINER):/etc/nginx/nginx.conf
270266
@docker exec $(CONTAINER) nginx -t
271267
@docker exec $(CONTAINER) supervisorctl -c /etc/supervisor/supervisord.conf restart appos nginx
@@ -963,11 +959,6 @@ endif
963959
# Container Management
964960
# ============================================================
965961
start:
966-
@if grep -q '^APPOS_SECRET_KEY=replace-with-a-random-base64-secret' build/.env 2>/dev/null; then \
967-
NEW_KEY=$$(openssl rand -base64 32); \
968-
sed -i "s|^APPOS_SECRET_KEY=replace-with-a-random-base64-secret|APPOS_SECRET_KEY=$$NEW_KEY|" build/.env; \
969-
echo "✓ Generated APPOS_SECRET_KEY in build/.env"; \
970-
fi
971962
@if [ "$(ARG2)" = "dev" ] || [ "$(ARG2)" = "latest" ]; then \
972963
IMAGE_TAG=$(ARG2); \
973964
PORT=9091; \

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,9 @@ OS for Your self-hosted Apps
77
- Do not write full story content in `epics.md`.
88
- Epic-level detail belongs in `specs/implementation-artifacts/epic*.md`.
99
- Implementation-ready story detail belongs in `specs/implementation-artifacts/story*.md`.
10+
11+
## Install
12+
13+
```
14+
docker run -d --name appos-demo --restart unless-stopped -p 9092:80 -p 9223:2222 -v /var/run/docker.sock:/var/run/docker.sock -v appos_data:/appos/data websoft9dev/appos:dev
15+
```

backend/docs/openapi/api.yaml

Lines changed: 4 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1899,7 +1899,7 @@ paths:
18991899
- Apps
19001900
/api/apps/{id}/config:
19011901
get:
1902-
description: Returns docker-compose.yml content for one installed app. Supports local and remote servers. Superuser only.
1902+
description: Returns docker-compose.yml content for one installed app on a managed server. Superuser only.
19031903
operationId: get_api_apps_id_config
19041904
parameters:
19051905
- description: app instance ID
@@ -1950,7 +1950,7 @@ paths:
19501950
tags:
19511951
- Apps
19521952
put:
1953-
description: Overwrites docker-compose.yml for one installed app. Supports local and remote servers. Superuser only.
1953+
description: Overwrites docker-compose.yml for one installed app on a managed server. Superuser only.
19541954
operationId: put_api_apps_id_config
19551955
parameters:
19561956
- description: app instance ID
@@ -2009,7 +2009,7 @@ paths:
20092009
- Apps
20102010
/api/apps/{id}/config/rollback:
20112011
post:
2012-
description: Restores the latest saved docker-compose rollback point for one installed app. Supports local and remote servers. Superuser only.
2012+
description: Restores the latest saved docker-compose rollback point for one installed app on a managed server. Superuser only.
20132013
operationId: post_api_apps_id_config_rollback
20142014
parameters:
20152015
- description: app instance ID
@@ -2067,7 +2067,7 @@ paths:
20672067
- Apps
20682068
/api/apps/{id}/config/validate:
20692069
post:
2070-
description: Validates draft docker-compose.yml content for one installed app before saving. Supports local and remote servers. Superuser only.
2070+
description: Validates draft docker-compose.yml content for one installed app on a managed server before saving. Superuser only.
20712071
operationId: post_api_apps_id_config_validate
20722072
parameters:
20732073
- description: app instance ID
@@ -11935,27 +11935,6 @@ paths:
1193511935
summary: List Docker servers
1193611936
tags:
1193711937
- Docker
11938-
/api/servers/local/docker-bridge:
11939-
get:
11940-
operationId: get_api_servers_local_docker-bridge
11941-
responses:
11942-
"200":
11943-
content:
11944-
application/json:
11945-
schema:
11946-
$ref: '#/components/schemas/SuccessEnvelope'
11947-
description: OK
11948-
"401":
11949-
content:
11950-
application/json:
11951-
schema:
11952-
$ref: '#/components/schemas/ErrorEnvelope'
11953-
description: Unauthorized
11954-
security:
11955-
- bearerAuth: []
11956-
summary: Get servers local docker bridge
11957-
tags:
11958-
- Servers
1195911938
/api/settings:
1196011939
get:
1196111940
operationId: pb_settings_get

backend/docs/openapi/ext-api.yaml

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1718,7 +1718,7 @@ paths:
17181718
get:
17191719
tags: [Apps]
17201720
summary: Get app compose config
1721-
description: "Returns docker-compose.yml content for one installed app. Supports local and remote servers. Superuser only."
1721+
description: "Returns docker-compose.yml content for one installed app on a managed server. Superuser only."
17221722
operationId: get_api_apps_id_config
17231723
parameters:
17241724
- name: id
@@ -1768,7 +1768,7 @@ paths:
17681768
put:
17691769
tags: [Apps]
17701770
summary: Write app compose config
1771-
description: "Overwrites docker-compose.yml for one installed app. Supports local and remote servers. Superuser only."
1771+
description: "Overwrites docker-compose.yml for one installed app on a managed server. Superuser only."
17721772
operationId: put_api_apps_id_config
17731773
parameters:
17741774
- name: id
@@ -1826,7 +1826,7 @@ paths:
18261826
post:
18271827
tags: [Apps]
18281828
summary: Roll back app compose config
1829-
description: "Restores the latest saved docker-compose rollback point for one installed app. Supports local and remote servers. Superuser only."
1829+
description: "Restores the latest saved docker-compose rollback point for one installed app on a managed server. Superuser only."
18301830
operationId: post_api_apps_id_config_rollback
18311831
parameters:
18321832
- name: id
@@ -1883,7 +1883,7 @@ paths:
18831883
post:
18841884
tags: [Apps]
18851885
summary: Validate app compose config
1886-
description: "Validates draft docker-compose.yml content for one installed app before saving. Supports local and remote servers. Superuser only."
1886+
description: "Validates draft docker-compose.yml content for one installed app on a managed server before saving. Superuser only."
18871887
operationId: post_api_apps_id_config_validate
18881888
parameters:
18891889
- name: id
@@ -7196,26 +7196,6 @@ paths:
71967196
application/json:
71977197
schema:
71987198
$ref: '#/components/schemas/ErrorEnvelope'
7199-
/api/servers/local/docker-bridge:
7200-
get:
7201-
tags: [Servers]
7202-
summary: Get servers local docker bridge
7203-
operationId: get_api_servers_local_docker-bridge
7204-
security:
7205-
- bearerAuth: [] # superuser required
7206-
responses:
7207-
"200":
7208-
description: OK
7209-
content:
7210-
application/json:
7211-
schema:
7212-
$ref: '#/components/schemas/SuccessEnvelope'
7213-
"401":
7214-
description: Unauthorized
7215-
content:
7216-
application/json:
7217-
schema:
7218-
$ref: '#/components/schemas/ErrorEnvelope'
72197199
/api/servers/{serverId}/docker/compose/config:
72207200
get:
72217201
tags: [Docker]

backend/docs/openapi/group-matrix.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,6 @@ groups:
447447
extSurface:
448448
- GET /api/servers/docker-targets
449449
- GET /api/servers/connection
450-
- GET /api/servers/local/docker-bridge
451450
- GET /api/servers/{serverId}/ops/connectivity
452451
- POST /api/servers/{serverId}/ops/power
453452
- GET /api/servers/{serverId}/ops/ports

backend/domain/lifecycle/runtime/deployment_targets.go

Lines changed: 16 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package runtime
22

33
import (
44
"context"
5-
"os"
5+
"fmt"
66
"path/filepath"
77

88
"github.com/pocketbase/pocketbase/core"
@@ -33,29 +33,6 @@ type Executor interface {
3333
Name() string
3434
}
3535

36-
type localExecutor struct {
37-
app core.App
38-
}
39-
40-
func (e localExecutor) PrepareWorkspace(projectDir string, compose string) error {
41-
if err := os.MkdirAll(projectDir, 0o755); err != nil {
42-
return err
43-
}
44-
return os.WriteFile(filepath.Join(projectDir, "docker-compose.yml"), []byte(compose), 0o600)
45-
}
46-
47-
func (e localExecutor) DockerClient() (*docker.Client, error) {
48-
exec := docker.NewLocalExecutor("")
49-
if os.Getuid() != 0 {
50-
exec.SudoEnabled = true
51-
}
52-
return docker.New(exec), nil
53-
}
54-
55-
func (e localExecutor) Name() string {
56-
return "local"
57-
}
58-
5936
type sshExecutor struct {
6037
app core.App
6138
serverID string
@@ -127,18 +104,25 @@ func (e sshExecutor) factory() sftpClientFactory {
127104
return defaultSFTPClientFactory
128105
}
129106

130-
func executorName(serverID string) string {
107+
func NewDeploymentExecutor(app core.App, serverID string) Executor {
131108
if serverID == "" || serverID == "local" {
132-
return "local"
109+
return unsupportedExecutor{}
133110
}
134-
return "ssh"
111+
return newSSHExecutor(app, serverID)
135112
}
136113

137-
func NewDeploymentExecutor(app core.App, serverID string) Executor {
138-
if executorName(serverID) == "local" {
139-
return localExecutor{app: app}
140-
}
141-
return newSSHExecutor(app, serverID)
114+
type unsupportedExecutor struct{}
115+
116+
func (unsupportedExecutor) PrepareWorkspace(string, string) error {
117+
return fmt.Errorf("managed server is required for deployment execution")
118+
}
119+
120+
func (unsupportedExecutor) DockerClient() (*docker.Client, error) {
121+
return nil, fmt.Errorf("managed server is required for deployment execution")
122+
}
123+
124+
func (unsupportedExecutor) Name() string {
125+
return "unsupported"
142126
}
143127

144128
func newSSHExecutor(app core.App, serverID string) sshExecutor {

backend/domain/lifecycle/runtime/deployment_targets_test.go

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package runtime
33
import (
44
"context"
55
"errors"
6-
"os"
76
"path/filepath"
87
"testing"
98

@@ -43,8 +42,8 @@ func TestNewDeploymentExecutor(t *testing.T) {
4342
serverID string
4443
wantName string
4544
}{
46-
{name: "empty server id", serverID: "", wantName: "local"},
47-
{name: "explicit local", serverID: "local", wantName: "local"},
45+
{name: "empty server id", serverID: "", wantName: "unsupported"},
46+
{name: "explicit local", serverID: "local", wantName: "unsupported"},
4847
{name: "remote id", serverID: "srv-1", wantName: "ssh"},
4948
}
5049

@@ -58,22 +57,10 @@ func TestNewDeploymentExecutor(t *testing.T) {
5857
}
5958
}
6059

61-
func TestLocalExecutorPrepareWorkspace(t *testing.T) {
62-
tmpDir := t.TempDir()
63-
projectDir := filepath.Join(tmpDir, "project")
64-
compose := "services:\n web:\n image: nginx:alpine\n"
65-
66-
exec := localExecutor{}
67-
if err := exec.PrepareWorkspace(projectDir, compose); err != nil {
68-
t.Fatalf("PrepareWorkspace returned error: %v", err)
69-
}
70-
71-
data, err := os.ReadFile(filepath.Join(projectDir, "docker-compose.yml"))
72-
if err != nil {
73-
t.Fatalf("failed to read docker-compose.yml: %v", err)
74-
}
75-
if got := string(data); got != compose {
76-
t.Fatalf("unexpected compose content: got %q want %q", got, compose)
60+
func TestUnsupportedExecutorRejectsWorkspacePreparation(t *testing.T) {
61+
exec := NewDeploymentExecutor(nil, "")
62+
if err := exec.PrepareWorkspace(filepath.Join(t.TempDir(), "project"), "services: {}\n"); err == nil {
63+
t.Fatal("expected unsupported executor to reject workspace preparation")
7764
}
7865
}
7966

backend/domain/lifecycle/runtime/node_executor.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,6 @@ func runtimeExecutorApp(executor Executor) core.App {
3636
return typed.App()
3737
}
3838
switch typed := executor.(type) {
39-
case localExecutor:
40-
return typed.app
41-
case *localExecutor:
42-
return typed.app
4339
case sshExecutor:
4440
return typed.app
4541
case *sshExecutor:

backend/domain/monitor/signals/platform/observer.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package platform
22

33
import (
44
"context"
5+
"fmt"
56
"log/slog"
67
"os"
78
"runtime"
@@ -11,21 +12,22 @@ import (
1112
"github.com/websoft9/appos/backend/domain/monitor"
1213
monitormetrics "github.com/websoft9/appos/backend/domain/monitor/metrics"
1314
monitorstatus "github.com/websoft9/appos/backend/domain/monitor/status"
14-
"github.com/websoft9/appos/backend/infra/docker"
1515
"github.com/websoft9/appos/backend/infra/supervisor"
1616
)
1717

18-
func NewPlatformObserver(app core.App, snapshotFn func() RuntimeSnapshot) *PlatformObserver {
19-
localDockerClient := docker.New(docker.NewLocalExecutor(""))
18+
func localContainerStatsDisabled(context.Context) (string, error) {
19+
return "", fmt.Errorf("local docker daemon access disabled")
20+
}
2021

22+
func NewPlatformObserver(app core.App, snapshotFn func() RuntimeSnapshot) *PlatformObserver {
2123
return &PlatformObserver{
2224
app: app,
2325
snapshotFn: snapshotFn,
2426
resourceFn: supervisor.GetProcessResources,
2527
appCoreTelemetryFn: collectLocalAppCoreMetricPoints,
2628
appCoreMemoryFn: readLocalAppCoreMemory,
2729
hostTelemetryFn: collectLocalHostMetricPoints,
28-
containerStatsFn: localDockerClient.ContainerStats,
30+
containerStatsFn: localContainerStatsDisabled,
2931
containerSamples: map[string]localContainerCounters{},
3032
nowFn: func() time.Time {
3133
return time.Now().UTC()

backend/domain/resource/servers/docker_runtime.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@ import (
99
)
1010

1111
// NewDockerClient returns a Docker client bound to the requested server.
12-
// When serverID is empty or "local", the provided localClient is returned.
13-
func NewDockerClient(app core.App, serverID string, localClient *docker.Client) (*docker.Client, error) {
12+
// Local Docker daemon access is intentionally unsupported; callers must
13+
// provide a managed server target that resolves to SSH.
14+
func NewDockerClient(app core.App, serverID string) (*docker.Client, error) {
1415
if serverID == "" || serverID == "local" {
15-
return localClient, nil
16+
return nil, fmt.Errorf("managed server is required for docker operations")
1617
}
1718

1819
server, err := LoadManagedServer(app, serverID)

0 commit comments

Comments
 (0)