diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index faabfbc..46f41d1 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,4 +1,9 @@ { "dockerComposeFile": "docker-compose.yml", "service": "lapdev", + "portsAttributes": { + "8080": { + "label": "dashboard", + } + } } \ No newline at end of file diff --git a/lapdev-common/src/lib.rs b/lapdev-common/src/lib.rs index dd3df59..729a9b6 100644 --- a/lapdev-common/src/lib.rs +++ b/lapdev-common/src/lib.rs @@ -357,6 +357,8 @@ pub struct WorkspaceService { #[derive(Serialize, Deserialize, Debug, Clone)] pub struct HostWorkspace { pub id: Uuid, + pub name: String, + pub osuser: String, pub ssh_port: Option, pub ide_port: Option, pub last_inactivity: Option>, diff --git a/lapdev-conductor/src/rpc.rs b/lapdev-conductor/src/rpc.rs index 568f867..3746a0e 100644 --- a/lapdev-conductor/src/rpc.rs +++ b/lapdev-conductor/src/rpc.rs @@ -83,6 +83,8 @@ impl ConductorService for ConductorRpc { .into_iter() .map(|ws| HostWorkspace { id: ws.id, + name: ws.name, + osuser: ws.osuser, ssh_port: ws.ssh_port, ide_port: ws.ide_port, last_inactivity: ws.last_inactivity, diff --git a/lapdev-conductor/src/server.rs b/lapdev-conductor/src/server.rs index ad0687a..52fb5f3 100644 --- a/lapdev-conductor/src/server.rs +++ b/lapdev-conductor/src/server.rs @@ -481,6 +481,7 @@ impl Conductor { let _ = rpc_future.await; tracing::debug!("workspace host connection ended"); + abort_handle.abort(); } Ok(()) diff --git a/lapdev-dashboard/src/workspace.rs b/lapdev-dashboard/src/workspace.rs index d9e0473..90f442c 100644 --- a/lapdev-dashboard/src/workspace.rs +++ b/lapdev-dashboard/src/workspace.rs @@ -410,7 +410,7 @@ fn WorkspaceControl( href="#" class="block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white" on:click=stop_workspace - class:hidden=move || workspace_status != WorkspaceStatus::Running && workspace_status != WorkspaceStatus::Stopping + class:hidden=move || workspace_status == WorkspaceStatus::Stopped > Stop diff --git a/lapdev-ws/src/server.rs b/lapdev-ws/src/server.rs index 0427c12..e7c5de1 100644 --- a/lapdev-ws/src/server.rs +++ b/lapdev-ws/src/server.rs @@ -20,8 +20,9 @@ use lapdev_common::{ devcontainer::{ DevContainerCmd, DevContainerConfig, DevContainerCwd, DevContainerLifeCycleCmd, }, - utils, BuildTarget, ContainerImageInfo, CpuCore, GitBranch, HostWorkspace, ProjectRequest, - RepoBuildInfo, RepoBuildOutput, RepoBuildResult, RepoComposeService, RepobuildError, + utils, BuildTarget, ContainerImageInfo, ContainerInfo, CpuCore, GitBranch, HostWorkspace, + ProjectRequest, RepoBuildInfo, RepoBuildOutput, RepoBuildResult, RepoComposeService, + RepobuildError, StartWorkspaceRequest, }; use lapdev_rpc::{ error::ApiError, spawn_twoway, ConductorServiceClient, InterWorkspaceService, WorkspaceService, @@ -48,7 +49,8 @@ use crate::{ pub const LAPDEV_WS_VERSION: &str = env!("CARGO_PKG_VERSION"); const INSTALL_SCRIPT: &[u8] = include_bytes!("../scripts/install_guest_agent.sh"); -const LAPDEV_GUEST_AGENT: &[u8] = include_bytes!("../../target/release/lapdev-guest-agent"); +const LAPDEV_GUEST_AGENT: &[u8] = + include_bytes!("../../target/x86_64-unknown-linux-musl/release/lapdev-guest-agent"); #[derive(Clone, Deserialize, Default)] #[serde(rename_all = "kebab-case")] @@ -175,6 +177,7 @@ impl WorkspaceServer { }); } + let mut startup_task_run = false; while let Some(conn) = listener.next().await { if let Ok(conn) = conn { let peer_addr = conn.peer_addr(); @@ -203,6 +206,16 @@ impl WorkspaceServer { tracing::info!("incoming conductor connection {peer_addr:?} stopped"); rpcs.write().await.retain(|rpc| rpc.id != id); }); + + if !startup_task_run { + startup_task_run = true; + let server = self.clone(); + tokio::spawn(async move { + if let Err(e) = server.run_startup_task().await { + tracing::error!("run start up task error: {e:?}"); + } + }); + } } } @@ -233,6 +246,29 @@ impl WorkspaceServer { } } + async fn run_startup_task(&self) -> Result<(), ApiError> { + tracing::info!("run startup task"); + let rpc = { self.rpcs.read().await.first().cloned() }; + let rpc = rpc.ok_or_else(|| anyhow!("don't have any conductor connections"))?; + let workspaces = rpc + .conductor_client + .running_workspaces_on_host(current()) + .await??; + for ws in workspaces { + if let Err(e) = self + .start_workspace(StartWorkspaceRequest { + osuser: ws.osuser, + workspace_name: ws.name.clone(), + }) + .await + { + tracing::error!("on startup task, start workspace {} error: {e:?}", ws.name); + } + } + + Ok(()) + } + async fn run_auto_stop_delete_task(&self) -> Result<(), ApiError> { let rpc = { self.rpcs.read().await.first().cloned() }; let rpc = rpc.ok_or_else(|| anyhow!("don't have any conductor connections"))?; @@ -1458,6 +1494,47 @@ driver = "overlay" Ok(branches) } + + pub async fn start_workspace( + &self, + ws_req: StartWorkspaceRequest, + ) -> Result { + let socket = self.get_podman_socket(&ws_req.osuser).await?; + let client = unix_client(); + let url = Uri::new( + &socket, + &format!("/containers/{}/start", ws_req.workspace_name), + ); + let req = hyper::Request::builder() + .method(hyper::Method::POST) + .uri(url) + .body(Full::::new(Bytes::new()))?; + let resp = client.request(req).await?; + let status = resp.status(); + let body = resp.collect().await?.to_bytes(); + if status != 204 && status != 304 { + let err = String::from_utf8(body.to_vec())?; + return Err(anyhow!("start container error: {err}").into()); + } + + let url = Uri::new( + &socket, + &format!("/containers/{}/json", ws_req.workspace_name), + ); + let req = hyper::Request::builder() + .method(hyper::Method::GET) + .uri(url) + .body(Full::::new(Bytes::new()))?; + let resp = client.request(req).await?; + let status = resp.status(); + let body = resp.collect().await?.to_bytes(); + if status != 200 { + let err = String::from_utf8(body.to_vec())?; + return Err(anyhow!("get container info error: {err}").into()); + } + let info: ContainerInfo = serde_json::from_slice(&body)?; + Ok(info) + } } async fn spawn(fut: impl futures::Future + Send + 'static) { diff --git a/lapdev-ws/src/service.rs b/lapdev-ws/src/service.rs index 4dda8f7..526d2a2 100644 --- a/lapdev-ws/src/service.rs +++ b/lapdev-ws/src/service.rs @@ -265,41 +265,7 @@ impl WorkspaceService for WorkspaceRpcService { _context: context::Context, ws_req: StartWorkspaceRequest, ) -> Result { - let socket = self.server.get_podman_socket(&ws_req.osuser).await?; - let client = unix_client(); - let url = Uri::new( - &socket, - &format!("/containers/{}/start", ws_req.workspace_name), - ); - let req = hyper::Request::builder() - .method(hyper::Method::POST) - .uri(url) - .body(Full::::new(Bytes::new()))?; - let resp = client.request(req).await?; - let status = resp.status(); - let body = resp.collect().await?.to_bytes(); - if status != 204 { - let err = String::from_utf8(body.to_vec())?; - return Err(anyhow!("start container error: {err}").into()); - } - - let url = Uri::new( - &socket, - &format!("/containers/{}/json", ws_req.workspace_name), - ); - let req = hyper::Request::builder() - .method(hyper::Method::GET) - .uri(url) - .body(Full::::new(Bytes::new()))?; - let resp = client.request(req).await?; - let status = resp.status(); - let body = resp.collect().await?.to_bytes(); - if status != 200 { - let err = String::from_utf8(body.to_vec())?; - return Err(anyhow!("get container info error: {err}").into()); - } - let info: ContainerInfo = serde_json::from_slice(&body)?; - Ok(info) + self.server.start_workspace(ws_req).await } async fn delete_workspace( diff --git a/pkg/image/fluxbox/Dockerfile b/pkg/image/fluxbox/Dockerfile index b29040a..b5b81ba 100644 --- a/pkg/image/fluxbox/Dockerfile +++ b/pkg/image/fluxbox/Dockerfile @@ -1,7 +1,7 @@ FROM debian:12 USER root -COPY ../../../target/release/lapdev-guest-agent /lapdev-guest-agent +COPY ../../../target/x86_64-unknown-linux-musl/release/lapdev-guest-agent /lapdev-guest-agent RUN chmod +x /lapdev-guest-agent COPY ../../../lapdev-ws/scripts/install_guest_agent.sh /install_guest_agent.sh RUN sh /install_guest_agent.sh diff --git a/pkg/image/gnome/Dockerfile b/pkg/image/gnome/Dockerfile index f4337af..5cff4d2 100644 --- a/pkg/image/gnome/Dockerfile +++ b/pkg/image/gnome/Dockerfile @@ -54,7 +54,7 @@ RUN apt-get update && \ /cleanup USER root -COPY ../../../target/release/lapdev-guest-agent /lapdev-guest-agent +COPY ../../../target/x86_64-unknown-linux-musl/release/lapdev-guest-agent /lapdev-guest-agent RUN chmod +x /lapdev-guest-agent COPY ../../../lapdev-ws/scripts/install_guest_agent.sh /install_guest_agent.sh RUN sh /install_guest_agent.sh diff --git a/pkg/image/go/Dockerfile b/pkg/image/go/Dockerfile index 8624ec4..350b15f 100644 --- a/pkg/image/go/Dockerfile +++ b/pkg/image/go/Dockerfile @@ -1,7 +1,7 @@ FROM mcr.microsoft.com/devcontainers/go:latest USER root -COPY ../../../target/release/lapdev-guest-agent /lapdev-guest-agent +COPY ../../../target/x86_64-unknown-linux-musl/release/lapdev-guest-agent /lapdev-guest-agent RUN chmod +x /lapdev-guest-agent COPY ../../../lapdev-ws/scripts/install_guest_agent.sh /install_guest_agent.sh RUN sh /install_guest_agent.sh diff --git a/pkg/image/javascript/Dockerfile b/pkg/image/javascript/Dockerfile index ed0b5eb..423052f 100644 --- a/pkg/image/javascript/Dockerfile +++ b/pkg/image/javascript/Dockerfile @@ -1,7 +1,7 @@ FROM mcr.microsoft.com/devcontainers/javascript-node:latest USER root -COPY ../../../target/release/lapdev-guest-agent /lapdev-guest-agent +COPY ../../../target/x86_64-unknown-linux-musl/release/lapdev-guest-agent /lapdev-guest-agent RUN chmod +x /lapdev-guest-agent COPY ../../../lapdev-ws/scripts/install_guest_agent.sh /install_guest_agent.sh RUN sh /install_guest_agent.sh diff --git a/pkg/image/lapdev/Dockerfile b/pkg/image/lapdev/Dockerfile new file mode 100644 index 0000000..442a758 --- /dev/null +++ b/pkg/image/lapdev/Dockerfile @@ -0,0 +1,16 @@ +FROM debian:12 + +RUN apt update +RUN apt install -y curl build-essential git vim podman pkg-config libssl-dev libz-dev fuse-overlayfs s3cmd + +RUN curl https://sh.rustup.rs -sSf | bash -s -- -y +RUN $HOME/.cargo/bin/rustup target add wasm32-unknown-unknown +RUN $HOME/.cargo/bin/rustup target add x86_64-unknown-linux-musl +RUN $HOME/.cargo/bin/cargo install trunk && rm -rf $HOME/.cargo/registry/ + +COPY ../../../target/x86_64-unknown-linux-musl/release/lapdev-guest-agent /lapdev-guest-agent +RUN chmod +x /lapdev-guest-agent +COPY ../../../lapdev-ws/scripts/install_guest_agent.sh /install_guest_agent.sh +RUN sh /install_guest_agent.sh && rm /install_guest_agent.sh + +EXPOSE 8080 diff --git a/pkg/image/python/Dockerfile b/pkg/image/python/Dockerfile index 2c86dc6..537722d 100644 --- a/pkg/image/python/Dockerfile +++ b/pkg/image/python/Dockerfile @@ -1,7 +1,7 @@ FROM mcr.microsoft.com/devcontainers/python:latest USER root -COPY ../../../target/release/lapdev-guest-agent /lapdev-guest-agent +COPY ../../../target/x86_64-unknown-linux-musl/release/lapdev-guest-agent /lapdev-guest-agent RUN chmod +x /lapdev-guest-agent COPY ../../../lapdev-ws/scripts/install_guest_agent.sh /install_guest_agent.sh RUN sh /install_guest_agent.sh diff --git a/pkg/image/rust/Dockerfile b/pkg/image/rust/Dockerfile index fb77e28..c271608 100644 --- a/pkg/image/rust/Dockerfile +++ b/pkg/image/rust/Dockerfile @@ -1,7 +1,7 @@ FROM mcr.microsoft.com/devcontainers/rust:latest USER root -COPY ../../../target/release/lapdev-guest-agent /lapdev-guest-agent +COPY ../../../target/x86_64-unknown-linux-musl/release/lapdev-guest-agent /lapdev-guest-agent RUN chmod +x /lapdev-guest-agent COPY ../../../lapdev-ws/scripts/install_guest_agent.sh /install_guest_agent.sh RUN sh /install_guest_agent.sh diff --git a/pkg/image/typescript/Dockerfile b/pkg/image/typescript/Dockerfile index 5d1b0a8..ccd27ed 100644 --- a/pkg/image/typescript/Dockerfile +++ b/pkg/image/typescript/Dockerfile @@ -1,7 +1,7 @@ FROM mcr.microsoft.com/devcontainers/typescript-node:latest USER root -COPY ../../../target/release/lapdev-guest-agent /lapdev-guest-agent +COPY ../../../target/x86_64-unknown-linux-musl/release/lapdev-guest-agent /lapdev-guest-agent RUN chmod +x /lapdev-guest-agent COPY ../../../lapdev-ws/scripts/install_guest_agent.sh /install_guest_agent.sh RUN sh /install_guest_agent.sh diff --git a/pkg/image/universal/Dockerfile b/pkg/image/universal/Dockerfile index 1db4930..31120c3 100644 --- a/pkg/image/universal/Dockerfile +++ b/pkg/image/universal/Dockerfile @@ -1,7 +1,7 @@ FROM mcr.microsoft.com/devcontainers/universal:latest USER root -COPY ../../../target/release/lapdev-guest-agent /lapdev-guest-agent +COPY ../../../target/x86_64-unknown-linux-musl/release/lapdev-guest-agent /lapdev-guest-agent RUN chmod +x /lapdev-guest-agent COPY ../../../lapdev-ws/scripts/install_guest_agent.sh /install_guest_agent.sh RUN sh /install_guest_agent.sh