@@ -442,4 +442,81 @@ export class Utils {
442442 }
443443 return lsFilesRes . stdout . split ( "\n" ) ;
444444 }
445+
446+ static async dockerVolumeFileExists ( containerExecutable : string , path : string , volume : string ) : Promise < boolean > {
447+ try {
448+ await Utils . spawn ( [ containerExecutable , "run" , "--rm" , "-v" , `${ volume } :/mnt/vol` , "alpine" , "ls" , `/mnt/vol/${ path } ` ] ) ;
449+ return true ;
450+ } catch {
451+ return false ;
452+ }
453+ }
454+
455+ static gclRegistryPrefix : string = "registry.gcl.local" ;
456+ static async startDockerRegistry ( argv : Argv ) : Promise < void > {
457+ const gclRegistryCertVol = `${ this . gclRegistryPrefix } .certs` ;
458+ const gclRegistryDataVol = `${ this . gclRegistryPrefix } .data` ;
459+ const gclRegistryNet = `${ this . gclRegistryPrefix } .net` ;
460+
461+ // create cert volume
462+ try {
463+ await Utils . spawn ( `${ argv . containerExecutable } volume create ${ gclRegistryCertVol } ` . split ( " " ) ) ;
464+ } catch ( err ) {
465+ if ( err instanceof Error && ! err . message . endsWith ( "already exists" ) )
466+ throw err ;
467+ }
468+
469+ // create self-signed cert/key files for https support
470+ if ( ! await this . dockerVolumeFileExists ( argv . containerExecutable , `${ this . gclRegistryPrefix } .crt` , gclRegistryCertVol ) ) {
471+ const opensslArgs = [
472+ "req" , "-newkey" , "rsa:4096" , "-nodes" , "-sha256" ,
473+ "-keyout" , `/certs/${ this . gclRegistryPrefix } .key` ,
474+ "-x509" , "-days" , "365" ,
475+ "-out" , `/certs/${ this . gclRegistryPrefix } .crt` ,
476+ "-subj" , `/CN=${ this . gclRegistryPrefix } ` ,
477+ "-addext" , `subjectAltName=DNS:${ this . gclRegistryPrefix } ` ,
478+ ] ;
479+ const generateCertsInPlace = [
480+ argv . containerExecutable , "run" , "--rm" , "-v" , `${ gclRegistryCertVol } :/certs` , "--entrypoint" , "sh" , "alpine/openssl" , "-c" ,
481+ [
482+ "openssl" , ...opensslArgs ,
483+ "&&" , "mkdir" , "-p" , `/certs/${ this . gclRegistryPrefix } ` ,
484+ "&&" , "cp" , `/certs/${ this . gclRegistryPrefix } .crt` , `/certs/${ this . gclRegistryPrefix } /ca.crt` ,
485+ ] . join ( " " ) ,
486+ ] ;
487+ await Utils . spawn ( generateCertsInPlace ) ;
488+ }
489+
490+ // create data volume
491+ try {
492+ await Utils . spawn ( [ argv . containerExecutable , "volume" , "create" , gclRegistryDataVol ] ) ;
493+ } catch ( err ) {
494+ if ( err instanceof Error && ! err . message . endsWith ( "already exists" ) )
495+ throw err ;
496+ }
497+
498+ // create network
499+ try {
500+ await Utils . spawn ( [ argv . containerExecutable , "network" , "create" , gclRegistryNet ] ) ;
501+ } catch ( err ) {
502+ if ( err instanceof Error && ! err . message . includes ( "already exists" ) )
503+ throw err ;
504+ }
505+
506+ await Utils . spawn ( [ argv . containerExecutable , "rm" , "-f" , this . gclRegistryPrefix ] ) ;
507+ await Utils . spawn ( [
508+ argv . containerExecutable , "run" , "-d" , "--name" , this . gclRegistryPrefix ,
509+ "--network" , gclRegistryNet ,
510+ "--volume" , `${ gclRegistryDataVol } :/var/lib/registry` ,
511+ "--volume" , `${ gclRegistryCertVol } :/certs:ro` ,
512+ "-e" , "REGISTRY_HTTP_ADDR=0.0.0.0:443" ,
513+ "-e" , `REGISTRY_HTTP_TLS_CERTIFICATE=/certs/${ this . gclRegistryPrefix } .crt` ,
514+ "-e" , `REGISTRY_HTTP_TLS_KEY=/certs/${ this . gclRegistryPrefix } .key` ,
515+ "registry" ,
516+ ] ) ;
517+ }
518+
519+ static async stopDockerRegistry ( containerExecutable : string ) : Promise < void > {
520+ await Utils . spawn ( [ containerExecutable , "rm" , "-f" , this . gclRegistryPrefix ] ) ;
521+ }
445522}
0 commit comments