@@ -4,7 +4,7 @@ Runner based on podman.
44
55import getLogger from "@cocalc/backend/logger" ;
66import { nodePath } from "./mounts" ;
7- import { isValidUUID } from "@cocalc/util/misc" ;
7+ import { isValidUUID , replace_all } from "@cocalc/util/misc" ;
88import { ensureConfFilesExists , setupDataPath , writeSecretToken } from "./util" ;
99import { getEnvironment } from "./env" ;
1010import { mkdir } from "fs/promises" ;
@@ -23,6 +23,8 @@ const children: { [project_id: string]: any } = {};
2323
2424const GRACE_PERIOD = 2000 ;
2525
26+ const info : { [ project_id : string ] : { home : string } } = { } ;
27+
2628export async function start ( {
2729 project_id,
2830 config,
@@ -39,7 +41,10 @@ export async function start({
3941 return ;
4042 }
4143
44+ const image = await getImage ( { project_id, config } ) ;
4245 const home = await mountHome ( project_id ) ;
46+ info [ project_id ] = { home } ;
47+
4348 await mkdir ( home , { recursive : true } ) ;
4449 await ensureConfFilesExists ( home ) ;
4550 const env = getEnvironment ( {
@@ -76,7 +81,7 @@ export async function start({
7681 args . push ( "-e" , `${ name } =${ env [ name ] } ` ) ;
7782 }
7883
79- args . push ( config ?. image ?? DEFAULT_IMAGE ) ;
84+ args . push ( image ) ;
8085 args . push ( nodePath ) ;
8186 args . push ( script , "--init" , "project_init.sh" ) ;
8287
@@ -148,6 +153,59 @@ export async function close() {
148153 await Promise . all ( v ) ;
149154}
150155
156+ export async function getImage ( { project_id, config } ) : Promise < string > {
157+ const { stdout } = await executeCode ( {
158+ err_on_exit : true ,
159+ command : "podman" ,
160+ args : [
161+ "images" ,
162+ "--filter" ,
163+ `reference=localhost/project/${ project_id } ` ,
164+ "--format=json" ,
165+ ] ,
166+ } ) ;
167+ const v = JSON . parse ( stdout ) ;
168+ return v [ 0 ] ?. Names ?. [ 0 ] ?? config ?. image ?? DEFAULT_IMAGE ;
169+ }
170+
171+ function nowTag ( ) {
172+ let s = new Date ( ) . toISOString ( ) ;
173+ const i = s . lastIndexOf ( ":" ) ;
174+ s = s . slice ( 0 , i ) ;
175+ return replace_all ( s , ":" , "-" ) ;
176+ }
177+
178+ export async function save ( {
179+ project_id,
180+ tag,
181+ } : {
182+ project_id : string ;
183+ tag ?: string ;
184+ } ) {
185+ const home = info [ project_id ] ?. home ?? ( await mountHome ( project_id ) ) ;
186+ const oci = join ( home , ".oci" ) ;
187+ await mkdir ( oci , { recursive : true } ) ;
188+ tag ??= nowTag ( ) ;
189+ const name = `localhost/project/${ project_id } :${ tag } ` ;
190+ await executeCode ( {
191+ err_on_exit : true ,
192+ command : "podman" ,
193+ // in seconds; can be long if lots of files/data
194+ timeout : 60 * 10 ,
195+ args : [ "commit" , `project-${ project_id } ` , name ] ,
196+ } ) ;
197+ await executeCode ( {
198+ err_on_exit : true ,
199+ command : "skopeo" ,
200+ timeout : 60 * 10 ,
201+ args : [
202+ "copy" ,
203+ `containers-storage:${ name } ` ,
204+ `oci:${ oci } :project-${ project_id } -${ tag } ` ,
205+ ] ,
206+ } ) ;
207+ }
208+
151209// important because it kills all
152210// the processes that were spawned
153211process . once ( "exit" , close ) ;
0 commit comments