@@ -428,13 +428,32 @@ func (m *DefaultManager) createAliasOverride(network string, routes []route) (st
428428 return file .Name (), nil
429429}
430430
431- func (m * DefaultManager ) ensureCaddy (network string , routes []route ) error {
431+ func (m * DefaultManager ) ensureCaddy (network string , routes []route ) ( err error ) {
432432 inspect := builder .NewCommand ("docker" , "inspect" , "--format" , "{{.State.Running}}" , caddyContainer )
433433 running , err := m .shell .Exec (inspect )
434434 ports := make (map [int ]bool )
435435 var preservedApps []byte
436436 var preservedAppsExist bool
437437 var preservedNetworks []string
438+ var originalPorts map [int ]bool
439+ expanding := false
440+ defer func () {
441+ if err == nil || ! expanding {
442+ return
443+ }
444+ _ = m .shell .Interactive (builder .NewCommand ("docker" , "rm" , "--force" ), caddyContainer )
445+ rollbackErr := m .createCaddy (originalPorts )
446+ if rollbackErr == nil {
447+ rollbackErr = m .connectCaddyNetworks (preservedNetworks )
448+ }
449+ if rollbackErr == nil {
450+ rollbackErr = m .waitForCaddy ()
451+ }
452+ if rollbackErr == nil && preservedAppsExist {
453+ rollbackErr = m .restoreApps (preservedApps , true )
454+ }
455+ err = errors .Join (err , rollbackErr )
456+ }()
438457 if err == nil {
439458 compatibility , inspectErr := m .shell .Exec (builder .NewCommand ("docker" , "inspect" , "--format" , "{{json .NetworkSettings.Networks}}|{{json .Config.Entrypoint}}|{{json .Config.Cmd}}" , caddyContainer ))
440459 if inspectErr != nil {
@@ -462,6 +481,7 @@ func (m *DefaultManager) ensureCaddy(network string, routes []route) error {
462481 for port := range parseContainerPorts (bindings ) {
463482 ports [port ] = true
464483 }
484+ originalPorts = copyPortSet (ports )
465485 networks , inspectErr := m .shell .Exec (builder .NewCommand ("docker" , "inspect" , "--format" , "{{json .NetworkSettings.Networks}}" , caddyContainer ))
466486 if inspectErr != nil {
467487 return inspectErr
@@ -470,44 +490,17 @@ func (m *DefaultManager) ensureCaddy(network string, routes []route) error {
470490 if err = m .shell .Interactive (builder .NewCommand ("docker" , "rm" , "--force" ), caddyContainer ); err != nil {
471491 return err
472492 }
493+ expanding = true
473494 err = errors .New ("proxy listener expansion required" )
474495 break
475496 }
476497 }
477498 }
478499 if err != nil {
479- configPath , configErr := m .ensureBaseConfig ()
480- if configErr != nil {
481- return configErr
482- }
483- if _ , networkErr := m .shell .Exec (builder .NewCommand ("docker" , "network" , "inspect" , caddyAdminNet )); networkErr != nil {
484- if networkErr = m .shell .Interactive (builder .NewCommand ("docker" , "network" , "create" ), caddyAdminNet ); networkErr != nil {
485- return networkErr
486- }
487- }
488- args := []string {"run" , "-d" , "--name" , caddyContainer , "--restart" , "unless-stopped" , "--network" , caddyAdminNet , "--network-alias" , caddyAdminHost , "-p" , "127.0.0.1:2019:2019" }
489500 for _ , route := range routes {
490501 ports [route .Listen ] = true
491502 }
492- var sortedPorts []int
493- for port := range ports {
494- sortedPorts = append (sortedPorts , port )
495- }
496- sort .Ints (sortedPorts )
497- for _ , port := range sortedPorts {
498- mapping := fmt .Sprintf ("%d:%d" , port , port )
499- args = append (args , "-p" , mapping )
500- }
501- args = append (args ,
502- "-v" , configPath + ":/etc/caddy/caddy.json:ro" ,
503- "-v" , caddyVolume + ":/var/lib/caddy" ,
504- "-e" , "XDG_CONFIG_HOME=/var/lib/caddy/config" ,
505- "-e" , "XDG_DATA_HOME=/var/lib/caddy/data" ,
506- "--entrypoint" , "/bin/sh" ,
507- caddyImage ,
508- "-c" , caddyStartCmd ,
509- )
510- if err = m .shell .Interactive (builder .NewCommand ("docker" ), args ... ); err != nil {
503+ if err = m .createCaddy (ports ); err != nil {
511504 return err
512505 }
513506 } else if running != "true" {
@@ -538,14 +531,59 @@ func (m *DefaultManager) ensureCaddy(network string, routes []route) error {
538531 return fmt .Errorf ("kool proxy does not publish port %d; remove %s and retry" , route .Listen , caddyContainer )
539532 }
540533 }
534+ if err = m .waitForCaddy (); err != nil {
535+ return err
536+ }
537+ if preservedAppsExist {
538+ if err = m .restoreApps (preservedApps , true ); err != nil {
539+ return err
540+ }
541+ }
542+ expanding = false
543+ return nil
544+ }
545+
546+ func (m * DefaultManager ) createCaddy (ports map [int ]bool ) error {
547+ configPath , err := m .ensureBaseConfig ()
548+ if err != nil {
549+ return err
550+ }
551+ if _ , err = m .shell .Exec (builder .NewCommand ("docker" , "network" , "inspect" , caddyAdminNet )); err != nil {
552+ if err = m .shell .Interactive (builder .NewCommand ("docker" , "network" , "create" ), caddyAdminNet ); err != nil {
553+ return err
554+ }
555+ }
556+ args := []string {"run" , "-d" , "--name" , caddyContainer , "--restart" , "unless-stopped" , "--network" , caddyAdminNet , "--network-alias" , caddyAdminHost , "-p" , "127.0.0.1:2019:2019" }
557+ var sortedPorts []int
558+ for port := range ports {
559+ sortedPorts = append (sortedPorts , port )
560+ }
561+ sort .Ints (sortedPorts )
562+ for _ , port := range sortedPorts {
563+ args = append (args , "-p" , fmt .Sprintf ("%d:%d" , port , port ))
564+ }
565+ args = append (args , "-v" , configPath + ":/etc/caddy/caddy.json:ro" , "-v" , caddyVolume + ":/var/lib/caddy" , "-e" , "XDG_CONFIG_HOME=/var/lib/caddy/config" , "-e" , "XDG_DATA_HOME=/var/lib/caddy/data" , "--entrypoint" , "/bin/sh" , caddyImage , "-c" , caddyStartCmd )
566+ return m .shell .Interactive (builder .NewCommand ("docker" ), args ... )
567+ }
568+
569+ func (m * DefaultManager ) connectCaddyNetworks (networks []string ) error {
570+ for _ , network := range networks {
571+ if network == caddyAdminNet {
572+ continue
573+ }
574+ if err := m .shell .Interactive (builder .NewCommand ("docker" , "network" , "connect" , network ), caddyContainer ); err != nil {
575+ return err
576+ }
577+ }
578+ return nil
579+ }
580+
581+ func (m * DefaultManager ) waitForCaddy () error {
541582 for attempt := 0 ; attempt < 30 ; attempt ++ {
542- response , requestErr := m .request (http .MethodGet , m .adminURL + "/config/" , nil )
543- if requestErr == nil {
583+ response , err := m .request (http .MethodGet , m .adminURL + "/config/" , nil )
584+ if err == nil {
544585 _ = response .Body .Close ()
545586 if response .StatusCode < 500 {
546- if preservedAppsExist {
547- return m .restoreApps (preservedApps , true )
548- }
549587 return nil
550588 }
551589 }
@@ -554,6 +592,14 @@ func (m *DefaultManager) ensureCaddy(network string, routes []route) error {
554592 return errors .New ("kool proxy did not become ready" )
555593}
556594
595+ func copyPortSet (ports map [int ]bool ) map [int ]bool {
596+ copy := make (map [int ]bool , len (ports ))
597+ for port := range ports {
598+ copy [port ] = true
599+ }
600+ return copy
601+ }
602+
557603func parseContainerPorts (raw string ) map [int ]bool {
558604 ports := make (map [int ]bool )
559605 var bindings map [string ]interface {}
0 commit comments