diff --git a/basefiles/app-compose.sh b/basefiles/app-compose.sh index 1f6c39479..59ee187c1 100644 --- a/basefiles/app-compose.sh +++ b/basefiles/app-compose.sh @@ -1,12 +1,39 @@ -#!/bin/sh -tdxctl notify-host -e "boot.progress" -d "starting containers" || true +#!/bin/bash -docker compose up --remove-orphans -d || true -chmod +x /usr/bin/containerd-shim-runc-v2 -systemctl restart docker +if [ $(jq 'has("pre_launch_script")' app-compose.json) == true ]; then + echo "Running pre-launch script" + tdxctl notify-host -e "boot.progress" -d "pre-launch" || true + source <(jq -r '.pre_launch_script' app-compose.json) +fi + +RUNNER=$(jq -r '.runner' app-compose.json) +case "$RUNNER" in +"docker-compose") + echo "Starting containers" + tdxctl notify-host -e "boot.progress" -d "starting containers" || true + if ! [ -f docker-compose.yaml ]; then + jq -r '.docker_compose_file' app-compose.json >docker-compose.yaml + fi + docker compose up --remove-orphans -d || true + chmod +x /usr/bin/containerd-shim-runc-v2 + systemctl restart docker -if ! docker compose up --remove-orphans -d; then - tdxctl notify-host -e "boot.error" -d "failed to start containers" + if ! docker compose up --remove-orphans -d; then + tdxctl notify-host -e "boot.error" -d "failed to start containers" + exit 1 + fi + ;; +"bash") + chmod +x /usr/bin/containerd-shim-runc-v2 + echo "Running main script" + tdxctl notify-host -e "boot.progress" -d "running main script" || true + jq -r '.bash_script' app-compose.json | bash + ;; +*) + echo "ERROR: unsupported runner: $RUNNER" >&2 + tdxctl notify-host -e "boot.error" -d "unsupported runner: $RUNNER" exit 1 -fi + ;; +esac + tdxctl notify-host -e "boot.progress" -d "done" || true diff --git a/tdxctl/src/tboot.rs b/tdxctl/src/tboot.rs index 1ebe03435..4b4949923 100644 --- a/tdxctl/src/tboot.rs +++ b/tdxctl/src/tboot.rs @@ -67,7 +67,6 @@ impl<'a> Setup<'a> { nc.notify_q("boot.progress", "setting up docker").await; self.setup_docker_registry()?; self.setup_docker_account()?; - self.prepare_docker_compose()?; Ok(()) } @@ -263,21 +262,6 @@ impl<'a> Setup<'a> { cmd!(docker login -u $username -p $token)?; Ok(()) } - - fn prepare_docker_compose(&self) -> Result<()> { - info!("Preparing docker compose"); - if self.app_compose.runner == "docker-compose" { - let docker_compose = self - .app_compose - .docker_compose_file - .as_ref() - .context("Missing docker_compose_file")?; - fs::write(self.resolve("/tapp/docker-compose.yaml"), docker_compose)?; - } else { - bail!("Unsupported runner: {}", self.app_compose.runner); - } - Ok(()) - } } pub async fn tboot(args: &TbootArgs) -> Result<()> { diff --git a/teepod/src/console.html b/teepod/src/console.html index 62491a0c0..c7d5ef469 100644 --- a/teepod/src/console.html +++ b/teepod/src/console.html @@ -521,10 +521,16 @@

Deploy a new instance

-
+
+ + +
+
App Information

Docker Compose File

{{ vm.appCompose?.docker_compose_file }}
+

Pre-launch Script

+
{{ vm.appCompose?.pre_launch_script }}
@@ -818,14 +827,25 @@

Update VM Config

-
- - +
+ + Update App Compose
-
- - +
+
+ + +
+
+ + +
+
+ + +
@@ -931,7 +951,8 @@

Derive VM

const vmForm = ref({ name: '', image: '', - compose_file: '', + dockerComposeFile: '', + preLaunchScript: '', vcpu: 1, memory: 1024, disk_size: 20, @@ -951,7 +972,9 @@

Derive VM

const upgradeDialog = ref({ show: false, vm: null, - compose_file: '', + updateCompose: false, + dockerComposeFile: '', + preLaunchScript: '', encrypted_envs: [], resetSecrets: false, vcpu: 0, @@ -1035,7 +1058,7 @@

Derive VM

"manifest_version": 2, "name": vmForm.value.name, "runner": "docker-compose", - "docker_compose_file": vmForm.value.compose_file, + "docker_compose_file": vmForm.value.dockerComposeFile, "docker_config": vmForm.value.docker_config.enabled ? { "username": vmForm.value.docker_config.username, "token_key": vmForm.value.docker_config.token_key, @@ -1045,6 +1068,11 @@

Derive VM

"public_logs": vmForm.value.public_logs, "public_sysinfo": vmForm.value.public_sysinfo }; + + if (vmForm.value.preLaunchScript?.trim()) { + app_compose.pre_launch_script = vmForm.value.preLaunchScript; + } + const imgFeatures = imageVersionFeatures(imageVersion(vmForm.value.image)); if (imgFeatures.compose_version < 2) { // Compatibility with old images @@ -1058,7 +1086,7 @@

Derive VM

return JSON.stringify(app_compose); }; - const appIdOf = async (composeFile) => { + const calcAppId = async () => { const app_compose = makeAppComposeFile(); const sha256Hash = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(app_compose)); return Array.from(new Uint8Array(sha256Hash)).map(b => b.toString(16).padStart(2, '0')).join('').slice(0, 40); @@ -1101,7 +1129,7 @@

Derive VM

const makeEncryptedEnv = async (envs, kmsEnabled, appId) => { if (!kmsEnabled || envs.length === 0) return ''; if (!appId) { - appId = await appIdOf(vmForm.value.compose_file); + appId = await calcAppId(); } const response = await rpcCall('GetAppEnvEncryptPubKey', { app_id: appId @@ -1233,7 +1261,7 @@

Derive VM

if (file) { const reader = new FileReader(); reader.onload = (e) => { - vmForm.value.compose_file = e.target.result; + vmForm.value.dockerComposeFile = e.target.result; }; reader.readAsText(file); } @@ -1253,7 +1281,9 @@

Derive VM

upgradeDialog.value = { show: true, vm: vm, - compose_file: '', + updateCompose: false, + dockerComposeFile: vm.appCompose.docker_compose_file, + preLaunchScript: vm.appCompose.pre_launch_script, resetSecrets: false, vcpu: vm.configuration?.vcpu, memory: vm.configuration?.memory, @@ -1268,7 +1298,7 @@

Derive VM

if (file) { const reader = new FileReader(); reader.onload = (e) => { - upgradeDialog.value.compose_file = e.target.result; + upgradeDialog.value.dockerComposeFile = e.target.result; }; reader.readAsText(file); } @@ -1294,12 +1324,13 @@

Derive VM

const body = { id: upgradeDialog.value.vm.id, }; - if (upgradeDialog.value.compose_file) { + if (upgradeDialog.value.updateCompose) { const currentAppCompose = upgradeDialog.value.vm.appCompose; const app_compose = { ...currentAppCompose, - docker_compose_file: upgradeDialog.value.compose_file + docker_compose_file: upgradeDialog.value.dockerComposeFile || currentAppCompose.docker_compose_file }; + app_compose.pre_launch_script = upgradeDialog.value.preLaunchScript?.trim(); body.compose_file = JSON.stringify(app_compose); } diff --git a/teepod/src/main_service.rs b/teepod/src/main_service.rs index 0e7c1359f..276413ef3 100644 --- a/teepod/src/main_service.rs +++ b/teepod/src/main_service.rs @@ -186,11 +186,8 @@ impl TeepodRpc for RpcHandler { runner: String, docker_compose_file: Option, } - let app_compose: AppCompose = + let _app_compose: AppCompose = serde_json::from_str(&request.compose_file).context("Invalid compose file")?; - if app_compose.docker_compose_file.is_none() { - bail!("Docker compose file cannot be empty"); - } } let compose_file_path = self.compose_file_path(&request.id); if !compose_file_path.exists() {