import * as Docker from 'dockerode' ; import { ProxySettingCallback } from 'mockttp' ; import { reportError } from '../../error-tracking' ; import { addShutdownHandler } from '../../shutdown' ; import { DOCKER_BUILD_LABEL } from './docker-build-injection' ; import { DOCKER_CONTAINER_LABEL } from './docker-commands' ; import { getDnsServer } from '../../dns-server' ; import { monitorDockerNetworkAliases , stopMonitoringDockerNetworkAliases } from './docker-networking' ; import { ensureDockerProxyRunning , stopDockerProxy } from './docker-proxy' ; import { prepareDockerTunnel , getDockerTunnelPort , ensureDockerTunnelRunning , stopDockerTunnel , } from './docker-tunnel-proxy' ; export const isDockerAvailable = ( ) => ( async ( ) => new Docker ( ) . ping ( ) ) ( ) . then ( ( ) => true ) . catch ( ( ) => false ) ; const IPv4_IPv6_PREFIX = "::ffff:" ; addShutdownHandler ( async ( ) => { if ( ! await isDockerAvailable ( ) ) return ; await deleteAllInterceptedDockerData ( 'all' ) ; } ) ; export async function startDockerInterceptionServices ( proxyPort , httpsConfig , ruleParameters ) { prepareDockerTunnel ( ) ; const networkMonitor = monitorDockerNetworkAliases ( proxyPort ) ; ruleParameters [ `docker-tunnel-proxy-${ proxyPort }` ] = async ( { hostname } ) => { hostname = hostname . startsWith ( IPv4_IPv6_PREFIX ) ? hostname . slice ( IPv4_IPv6_PREFIX . length ) : hostname ; if ( ( await networkMonitor ) ?. dockerRoutedAliases . has ( hostname ) ) { return { proxyUrl : `socks5://127.0.0.1:${ await getDockerTunnelPort ( proxyPort ) }` } ; } } ; await Promise . all ( [ ensureDockerProxyRunning ( proxyPort , httpsConfig ) , getDnsServer ( proxyPort ) , networkMonitor ] ) ; } export async function ensureDockerServicesRunning ( proxyPort ) { await Promise . all ( [ monitorDockerNetworkAliases ( proxyPort ) , ensureDockerTunnelRunning ( proxyPort ) , getDnsServer ( proxyPort ) ] ) . catch ( reportError ) ; } export async function stopDockerInterceptionServices ( proxyPort , ruleParameters ) { stopDockerProxy ( proxyPort ) ; stopMonitoringDockerNetworkAliases ( proxyPort ) ; await deleteAllInterceptedDockerData ( proxyPort ) ; delete ruleParameters [ `docker-tunnel-proxy-${ proxyPort }` ] ; } const pendingDeactivations = { } ; export async function deleteAllInterceptedDockerData ( proxyPort ) { if ( pendingDeactivations [ proxyPort ] ) return pendingDeactivations [ proxyPort ] ; if ( ! await isDockerAvailable ( ) ) return ; return pendingDeactivations [ proxyPort ] = Promise . all ( [ stopDockerTunnel ( proxyPort ) , ( async ( ) => { const docker = new Docker ( ) ; const containers = await docker . listContainers ( { all : true , filters : JSON . stringify ( { label : [ proxyPort === 'all' ? DOCKER_CONTAINER_LABEL : `${ DOCKER_CONTAINER_LABEL }=${ proxyPort }` ] } ) } ) ; await Promise . all ( containers . map ( async ( containerData ) => { const container = docker . getContainer ( containerData . Id ) ; await container . stop ( { t : 1 } ) . catch ( ( ) => { } ) ; await container . remove ( { force : true } ) . catch ( ( ) => { } ) ; } ) ) ; const images = await docker . listImages ( { all : true , filters : JSON . stringify ( { label : [ proxyPort === 'all' ? DOCKER_BUILD_LABEL : `${ DOCKER_BUILD_LABEL }=${ proxyPort }` ] } ) } ) ; await Promise . all ( images . map ( async ( imageData ) => { await docker . getImage ( imageData . Id ) . remove ( ) . catch ( ( ) => { } ) ; } ) ) ; delete pendingDeactivations [ proxyPort ] ; } ) ( ) ] ) as Promise < unknown > as Promise < void > ; }