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