fix: use host bind mount for /data/repos so tool containers can access mounted repos
The API container used a named Docker volume (repo_data:/data/repos) for storing repositories. When creating tool instances with direct mount mode, the API told Docker to bind-mount /data/repos/<repo>:/workspace into the tool container. But the Docker daemon resolves bind-mount paths on the HOST filesystem, not inside the API container. Since the host had no /data/repos (the repos only existed inside the named volume), tool containers mounted empty directories. Changed both compose files to use a host bind mount (/data/repos:/data/repos) instead of a named volume. This ensures: - The API container and tool containers both see the same /data/repos path - Bind mounts from /data/repos into tool containers work correctly For existing installations: repos previously stored in the repo_data named volume should be copied to /data/repos on the host before restarting the stack. Quality gates: compose file syntax valid
This commit is contained in:
@@ -25,11 +25,13 @@ interface UseInstanceActionsReturn {
|
||||
}
|
||||
|
||||
export function useInstanceActions(
|
||||
options: UseInstanceActionsOptions
|
||||
options: UseInstanceActionsOptions,
|
||||
): UseInstanceActionsReturn {
|
||||
const { onRefresh } = options;
|
||||
const [loadingSessionId, setLoadingSessionId] = useState<string | null>(null);
|
||||
const [dirtyDeleteSession, setDirtyDeleteSession] = useState<Session | null>(null);
|
||||
const [dirtyDeleteSession, setDirtyDeleteSession] = useState<Session | null>(
|
||||
null,
|
||||
);
|
||||
const [dirtyDeleteFiles, setDirtyDeleteFiles] = useState<string[]>([]);
|
||||
|
||||
const handleOpen = useCallback((session: Session) => {
|
||||
@@ -49,7 +51,11 @@ export function useInstanceActions(
|
||||
if (loadingSessionId === session.id) return;
|
||||
setLoadingSessionId(session.id);
|
||||
try {
|
||||
await startInstance(session.project_id, session.repository_id, session.id);
|
||||
await startInstance(
|
||||
session.project_id,
|
||||
session.repository_id,
|
||||
session.id,
|
||||
);
|
||||
await onRefresh();
|
||||
} catch {
|
||||
// ignore
|
||||
@@ -57,7 +63,7 @@ export function useInstanceActions(
|
||||
setLoadingSessionId(null);
|
||||
}
|
||||
},
|
||||
[loadingSessionId, onRefresh]
|
||||
[loadingSessionId, onRefresh],
|
||||
);
|
||||
|
||||
const handleStop = useCallback(
|
||||
@@ -65,7 +71,11 @@ export function useInstanceActions(
|
||||
if (loadingSessionId === session.id) return;
|
||||
setLoadingSessionId(session.id);
|
||||
try {
|
||||
await stopInstance(session.project_id, session.repository_id, session.id);
|
||||
await stopInstance(
|
||||
session.project_id,
|
||||
session.repository_id,
|
||||
session.id,
|
||||
);
|
||||
await onRefresh();
|
||||
} catch {
|
||||
// ignore
|
||||
@@ -73,7 +83,7 @@ export function useInstanceActions(
|
||||
setLoadingSessionId(null);
|
||||
}
|
||||
},
|
||||
[loadingSessionId, onRefresh]
|
||||
[loadingSessionId, onRefresh],
|
||||
);
|
||||
|
||||
const handleDelete = useCallback(
|
||||
@@ -81,13 +91,20 @@ export function useInstanceActions(
|
||||
if (loadingSessionId === session.id) return;
|
||||
setLoadingSessionId(session.id);
|
||||
try {
|
||||
await deleteInstance(session.project_id, session.repository_id, session.id);
|
||||
await deleteInstance(
|
||||
session.project_id,
|
||||
session.repository_id,
|
||||
session.id,
|
||||
);
|
||||
setDirtyDeleteSession(null);
|
||||
setDirtyDeleteFiles([]);
|
||||
await onRefresh();
|
||||
} catch (error) {
|
||||
const axiosError = error as {
|
||||
response?: { status?: number; data?: { detail?: { changed_files?: string[] } } };
|
||||
response?: {
|
||||
status?: number;
|
||||
data?: { detail?: { changed_files?: string[] } };
|
||||
};
|
||||
};
|
||||
if (axiosError.response?.status === 409) {
|
||||
const detail = axiosError.response.data?.detail;
|
||||
@@ -101,7 +118,7 @@ export function useInstanceActions(
|
||||
setLoadingSessionId(null);
|
||||
}
|
||||
},
|
||||
[loadingSessionId, onRefresh]
|
||||
[loadingSessionId, onRefresh],
|
||||
);
|
||||
|
||||
const handleForceDelete = useCallback(
|
||||
@@ -109,7 +126,12 @@ export function useInstanceActions(
|
||||
if (loadingSessionId === session.id) return;
|
||||
setLoadingSessionId(session.id);
|
||||
try {
|
||||
await deleteInstance(session.project_id, session.repository_id, session.id, true);
|
||||
await deleteInstance(
|
||||
session.project_id,
|
||||
session.repository_id,
|
||||
session.id,
|
||||
true,
|
||||
);
|
||||
setDirtyDeleteSession(null);
|
||||
setDirtyDeleteFiles([]);
|
||||
await onRefresh();
|
||||
@@ -119,7 +141,7 @@ export function useInstanceActions(
|
||||
setLoadingSessionId(null);
|
||||
}
|
||||
},
|
||||
[loadingSessionId, onRefresh]
|
||||
[loadingSessionId, onRefresh],
|
||||
);
|
||||
|
||||
const handleRecreateTunnel = useCallback(
|
||||
@@ -130,7 +152,7 @@ export function useInstanceActions(
|
||||
await recreateInstanceTunnel(
|
||||
session.project_id,
|
||||
session.repository_id,
|
||||
session.id
|
||||
session.id,
|
||||
);
|
||||
await onRefresh();
|
||||
} catch (err) {
|
||||
@@ -142,7 +164,7 @@ export function useInstanceActions(
|
||||
setLoadingSessionId(null);
|
||||
}
|
||||
},
|
||||
[loadingSessionId, onRefresh]
|
||||
[loadingSessionId, onRefresh],
|
||||
);
|
||||
|
||||
const clearDirtyDelete = useCallback(() => {
|
||||
|
||||
@@ -92,7 +92,7 @@ services:
|
||||
AUTHENTIK_AUTHORIZE_URL: ${AUTHENTIK_AUTHORIZE_URL:-}
|
||||
AUTHENTIK_TOKEN_URL: ${AUTHENTIK_TOKEN_URL:-}
|
||||
volumes:
|
||||
- repo_data:/data/repos
|
||||
- /data/repos:/data/repos
|
||||
- /data/instances:/data/instances
|
||||
- avatar_uploads:/app/uploads
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
@@ -116,7 +116,6 @@ services:
|
||||
volumes:
|
||||
postgres_data:
|
||||
redis_data:
|
||||
repo_data:
|
||||
avatar_uploads:
|
||||
|
||||
networks:
|
||||
|
||||
+1
-2
@@ -57,7 +57,7 @@ services:
|
||||
REPO_BASE_PATH: /data/repos
|
||||
INSTANCE_BASE_PATH: /data/instances
|
||||
volumes:
|
||||
- repo_data:/data/repos
|
||||
- /data/repos:/data/repos
|
||||
- /data/instances:/data/instances
|
||||
ports:
|
||||
- "8000:8000"
|
||||
@@ -91,7 +91,6 @@ services:
|
||||
volumes:
|
||||
postgres_data:
|
||||
redis_data:
|
||||
repo_data:
|
||||
|
||||
networks:
|
||||
backend:
|
||||
|
||||
Reference in New Issue
Block a user