@@ -41,7 +41,7 @@ type Endpoint interface {
4141 DriverInfo () (map [string ]interface {}, error )
4242
4343 // Delete and detaches this endpoint from the network.
44- Delete () error
44+ Delete (force bool ) error
4545}
4646
4747// EndpointOption is a option setter function type used to pass varios options to Network
@@ -56,6 +56,7 @@ type endpoint struct {
5656 iface * endpointInterface
5757 joinInfo * endpointJoinInfo
5858 sandboxID string
59+ locator string
5960 exposedPorts []types.TransportPort
6061 anonymous bool
6162 disableResolution bool
@@ -84,6 +85,7 @@ func (ep *endpoint) MarshalJSON() ([]byte, error) {
8485 epMap ["generic" ] = ep .generic
8586 }
8687 epMap ["sandbox" ] = ep .sandboxID
88+ epMap ["locator" ] = ep .locator
8789 epMap ["anonymous" ] = ep .anonymous
8890 epMap ["disableResolution" ] = ep .disableResolution
8991 epMap ["myAliases" ] = ep .myAliases
@@ -167,6 +169,9 @@ func (ep *endpoint) UnmarshalJSON(b []byte) (err error) {
167169 if v , ok := epMap ["disableResolution" ]; ok {
168170 ep .disableResolution = v .(bool )
169171 }
172+ if l , ok := epMap ["locator" ]; ok {
173+ ep .locator = l .(string )
174+ }
170175 ma , _ := json .Marshal (epMap ["myAliases" ])
171176 var myAliases []string
172177 json .Unmarshal (ma , & myAliases )
@@ -186,6 +191,7 @@ func (ep *endpoint) CopyTo(o datastore.KVObject) error {
186191 dstEp .name = ep .name
187192 dstEp .id = ep .id
188193 dstEp .sandboxID = ep .sandboxID
194+ dstEp .locator = ep .locator
189195 dstEp .dbIndex = ep .dbIndex
190196 dstEp .dbExists = ep .dbExists
191197 dstEp .anonymous = ep .anonymous
@@ -600,7 +606,23 @@ func (ep *endpoint) sbLeave(sbox Sandbox, options ...EndpointOption) error {
600606 return sb .clearDefaultGW ()
601607}
602608
603- func (ep * endpoint ) Delete () error {
609+ func (n * network ) validateForceDelete (locator string ) error {
610+ if n .Scope () == datastore .LocalScope {
611+ return nil
612+ }
613+
614+ if locator == "" {
615+ return fmt .Errorf ("invalid endpoint locator identifier" )
616+ }
617+
618+ if n .getController ().isNodeAlive (locator ) {
619+ return fmt .Errorf ("the remote host %s hosting the container is alive" , locator )
620+ }
621+
622+ return nil
623+ }
624+
625+ func (ep * endpoint ) Delete (force bool ) error {
604626 var err error
605627 n , err := ep .getNetworkFromStore ()
606628 if err != nil {
@@ -615,16 +637,31 @@ func (ep *endpoint) Delete() error {
615637 ep .Lock ()
616638 epid := ep .id
617639 name := ep .name
618- sb , _ := n .getController ().SandboxByID (ep .sandboxID )
619- if sb != nil {
620- ep .Unlock ()
640+ sbid := ep .sandboxID
641+ locator := ep .locator
642+ ep .Unlock ()
643+
644+ if force {
645+ if err = n .validateForceDelete (locator ); err != nil {
646+ return fmt .Errorf ("unable to force delete endpoint %s: %v" , name , err )
647+ }
648+ }
649+
650+ sb , _ := n .getController ().SandboxByID (sbid )
651+ if sb != nil && ! force {
621652 return & ActiveContainerError {name : name , id : epid }
622653 }
623- ep .Unlock ()
654+
655+ if sb != nil {
656+ if e := ep .sbLeave (sb ); e != nil {
657+ log .Warnf ("failed to leave sandbox for endpoint %s : %v" , name , e )
658+ }
659+ }
624660
625661 if err = n .getController ().deleteFromStore (ep ); err != nil {
626662 return err
627663 }
664+
628665 defer func () {
629666 if err != nil {
630667 ep .dbExists = false
@@ -648,7 +685,7 @@ func (ep *endpoint) Delete() error {
648685 // unwatch for service records
649686 n .getController ().unWatchSvcRecord (ep )
650687
651- if err = ep .deleteEndpoint (); err != nil {
688+ if err = ep .deleteEndpoint (); err != nil && ! force {
652689 return err
653690 }
654691
@@ -923,7 +960,7 @@ func (c *controller) cleanupLocalEndpoints() {
923960 }
924961
925962 for _ , ep := range epl {
926- if err := ep .Delete (); err != nil {
963+ if err := ep .Delete (false ); err != nil {
927964 log .Warnf ("Could not delete local endpoint %s during endpoint cleanup: %v" , ep .name , err )
928965 }
929966 }
0 commit comments