mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-13 05:12:55 -07:00
feat(offload): finalize verified single-command onboarding flow
This commit is contained in:
@@ -9,7 +9,8 @@ import os from 'os';
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Centralized SSH/RSYNC management for GCE Workers.
|
* Centralized SSH/RSYNC management for GCE Workers.
|
||||||
* Handles Magic Hostname routing, Zero-Knowledge security, and IAP Fallbacks.
|
* Handles Magic Hostname routing with Zero-Knowledge security.
|
||||||
|
* STRICTLY uses Direct Internal connection (Corporate Magic).
|
||||||
*/
|
*/
|
||||||
export class GceConnectionManager {
|
export class GceConnectionManager {
|
||||||
private projectId: string;
|
private projectId: string;
|
||||||
@@ -45,24 +46,11 @@ export class GceConnectionManager {
|
|||||||
|
|
||||||
run(command: string, options: { interactive?: boolean; stdio?: 'pipe' | 'inherit' } = {}): { status: number; stdout: string; stderr: string } {
|
run(command: string, options: { interactive?: boolean; stdio?: 'pipe' | 'inherit' } = {}): { status: number; stdout: string; stderr: string } {
|
||||||
const sshCmd = this.getRunCommand(command, options);
|
const sshCmd = this.getRunCommand(command, options);
|
||||||
|
const res = spawnSync(sshCmd, { stdio: options.stdio || 'pipe', shell: true });
|
||||||
// 1. Try Direct Path
|
|
||||||
const directRes = spawnSync(sshCmd, { stdio: options.stdio || 'pipe', shell: true });
|
|
||||||
if (directRes.status === 0) {
|
|
||||||
return {
|
|
||||||
status: 0,
|
|
||||||
stdout: directRes.stdout?.toString() || '',
|
|
||||||
stderr: directRes.stderr?.toString() || ''
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. Try IAP Fallback
|
|
||||||
const iapCmd = `gcloud compute ssh ${this.instanceName} --project ${this.projectId} --zone ${this.zone} --tunnel-through-iap --command ${this.quote(command)}`;
|
|
||||||
const iapRes = spawnSync(iapCmd, { stdio: options.stdio || 'pipe', shell: true });
|
|
||||||
return {
|
return {
|
||||||
status: iapRes.status ?? 1,
|
status: res.status ?? 1,
|
||||||
stdout: iapRes.stdout?.toString() || '',
|
stdout: res.stdout?.toString() || '',
|
||||||
stderr: iapRes.stderr?.toString() || ''
|
stderr: res.stderr?.toString() || ''
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,29 +60,11 @@ export class GceConnectionManager {
|
|||||||
if (options.delete) rsyncArgs.push('--delete');
|
if (options.delete) rsyncArgs.push('--delete');
|
||||||
if (options.exclude) options.exclude.forEach(ex => rsyncArgs.push(`--exclude="${ex}"`));
|
if (options.exclude) options.exclude.forEach(ex => rsyncArgs.push(`--exclude="${ex}"`));
|
||||||
|
|
||||||
// Ensure remote directory exists
|
|
||||||
const remoteParent = remotePath.endsWith('/') ? remotePath : remotePath.substring(0, remotePath.lastIndexOf('/'));
|
|
||||||
if (remoteParent) {
|
|
||||||
const mkdirRes = this.run(`mkdir -p ${remoteParent}`);
|
|
||||||
if (mkdirRes.status !== 0) {
|
|
||||||
console.error(` ❌ Failed to create remote directory ${remoteParent}: ${mkdirRes.stderr}`);
|
|
||||||
// We continue anyway as it might be a permission false positive on some OSs
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const sshCmd = `ssh ${this.getCommonArgs().join(' ')}`;
|
const sshCmd = `ssh ${this.getCommonArgs().join(' ')}`;
|
||||||
const directRsync = `rsync ${rsyncArgs.join(' ')} -e ${this.quote(sshCmd)} ${localPath} ${fullRemote}:${remotePath}`;
|
const directRsync = `rsync ${rsyncArgs.join(' ')} -e ${this.quote(sshCmd)} ${localPath} ${fullRemote}:${remotePath}`;
|
||||||
|
|
||||||
console.log(` - Attempting direct sync...`);
|
const res = spawnSync(directRsync, { stdio: 'inherit', shell: true });
|
||||||
const directRes = spawnSync(directRsync, { stdio: 'inherit', shell: true });
|
return res.status ?? 1;
|
||||||
if (directRes.status === 0) return 0;
|
|
||||||
|
|
||||||
console.log(` ⚠️ Direct sync failed, attempting IAP fallback...`);
|
|
||||||
const iapSshCmd = `gcloud compute ssh --project ${this.projectId} --zone ${this.zone} --tunnel-through-iap --quiet`;
|
|
||||||
const iapRsync = `rsync ${rsyncArgs.join(' ')} -e ${this.quote(iapSshCmd)} ${localPath} ${this.instanceName}:${remotePath}`;
|
|
||||||
const iapRes = spawnSync(iapRsync, { stdio: 'inherit', shell: true });
|
|
||||||
|
|
||||||
return iapRes.status ?? 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private quote(str: string) {
|
private quote(str: string) {
|
||||||
|
|||||||
@@ -61,12 +61,14 @@ export class GceCosProvider implements WorkerProvider {
|
|||||||
console.log(`🚀 Provisioning GCE COS worker: ${this.instanceName}...`);
|
console.log(`🚀 Provisioning GCE COS worker: ${this.instanceName}...`);
|
||||||
|
|
||||||
const startupScript = `#!/bin/bash
|
const startupScript = `#!/bin/bash
|
||||||
docker pull ${imageUri}
|
echo "🚀 Starting Maintainer Worker Deployment..."
|
||||||
|
docker pull ${imageUri} || echo "❌ Failed to pull image"
|
||||||
docker run -d --name maintainer-worker --restart always \\
|
docker run -d --name maintainer-worker --restart always \\
|
||||||
-v ~/.offload:/home/node/.offload:rw \\
|
-v ~/.offload:/home/node/.offload:rw \\
|
||||||
-v ~/dev:/home/node/dev:rw \\
|
-v ~/dev:/home/node/dev:rw \\
|
||||||
-v ~/.gemini:/home/node/.gemini:rw \\
|
-v ~/.gemini:/home/node/.gemini:rw \\
|
||||||
${imageUri} /bin/bash -c "while true; do sleep 1000; done"
|
${imageUri} /bin/bash -c "while true; do sleep 1000; done" || echo "❌ Failed to run container"
|
||||||
|
echo "✅ Deployment script finished."
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const result = spawnSync('gcloud', [
|
const result = spawnSync('gcloud', [
|
||||||
|
|||||||
Reference in New Issue
Block a user