Skip to content

Commit 3edcfd3

Browse files
committed
Forced endpoint delete
Signed-off-by: Madhu Venugopal <madhu@docker.com>
1 parent c8ec4bd commit 3edcfd3

File tree

10 files changed

+120
-42
lines changed

10 files changed

+120
-42
lines changed

api/api.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -529,7 +529,7 @@ func procDeleteEndpoint(c libnetwork.NetworkController, vars map[string]string,
529529
return nil, errRsp
530530
}
531531

532-
err := ep.Delete()
532+
err := ep.Delete(false)
533533
if err != nil {
534534
return nil, convertNetworkError(err)
535535
}
@@ -641,13 +641,22 @@ func procPublishService(c libnetwork.NetworkController, vars map[string]string,
641641
}
642642

643643
func procUnpublishService(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
644+
var sd serviceDelete
645+
646+
if body != nil {
647+
err := json.Unmarshal(body, &sd)
648+
if err != nil {
649+
return "", &responseStatus{Status: "Invalid body: " + err.Error(), StatusCode: http.StatusBadRequest}
650+
}
651+
}
652+
644653
epT, epBy := detectEndpointTarget(vars)
645654
sv, errRsp := findService(c, epT, epBy)
646655
if !errRsp.isOK() {
647656
return nil, errRsp
648657
}
649-
err := sv.Delete()
650-
if err != nil {
658+
659+
if err := sv.Delete(sd.Force); err != nil {
651660
return nil, endpointToService(convertNetworkError(err))
652661
}
653662
return nil, &successResponse

api/api_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -690,15 +690,15 @@ func TestProcGetServices(t *testing.T) {
690690
}
691691

692692
delete(vars, urlEpPID)
693-
err = ep11.Delete()
693+
err = ep11.Delete(false)
694694
if err != nil {
695695
t.Fatal(err)
696696
}
697-
err = ep12.Delete()
697+
err = ep12.Delete(false)
698698
if err != nil {
699699
t.Fatal(err)
700700
}
701-
err = ep21.Delete()
701+
err = ep21.Delete(false)
702702
if err != nil {
703703
t.Fatal(err)
704704
}
@@ -1014,7 +1014,7 @@ func TestAttachDetachBackend(t *testing.T) {
10141014
t.Fatalf("Did not find expected sandbox. Got %v", sb)
10151015
}
10161016

1017-
err = ep1.Delete()
1017+
err = ep1.Delete(false)
10181018
if err != nil {
10191019
t.Fatal(err)
10201020
}
@@ -1495,7 +1495,7 @@ func TestFindEndpointUtil(t *testing.T) {
14951495
t.Fatalf("Diffenrent queries returned different endpoints")
14961496
}
14971497

1498-
ep.Delete()
1498+
ep.Delete(false)
14991499

15001500
_, errRsp = findEndpoint(c, nid, "secondEp", byID, byName)
15011501
if errRsp == &successResponse {

api/types.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,12 @@ type servicePublish struct {
7676
PortMapping []types.PortBinding `json:"port_mapping"`
7777
}
7878

79+
// serviceDelete represents the body of the "unpublish service" http request message
80+
type serviceDelete struct {
81+
Name string `json:"name"`
82+
Force bool `json:"force"`
83+
}
84+
7985
// extraHost represents the extra host object
8086
type extraHost struct {
8187
Name string `json:"name"`

controller.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,31 @@ func (c *controller) validateHostDiscoveryConfig() bool {
216216
return true
217217
}
218218

219+
func (c *controller) clusterHostID() string {
220+
c.Lock()
221+
defer c.Unlock()
222+
if c.cfg == nil || c.cfg.Cluster.Address == "" {
223+
return ""
224+
}
225+
addr := strings.Split(c.cfg.Cluster.Address, ":")
226+
return addr[0]
227+
}
228+
229+
func (c *controller) isNodeAlive(node string) bool {
230+
if c.discovery == nil {
231+
return false
232+
}
233+
234+
nodes := c.discovery.Fetch()
235+
for _, n := range nodes {
236+
if n.String() == node {
237+
return true
238+
}
239+
}
240+
241+
return false
242+
}
243+
219244
func (c *controller) initDiscovery(watcher discovery.Watcher) error {
220245
if c.cfg == nil {
221246
return fmt.Errorf("discovery initialization requires a valid configuration")

default_gateway.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ func (sb *sandbox) clearDefaultGW() error {
8787
if err := ep.sbLeave(sb); err != nil {
8888
return fmt.Errorf("container %s: endpoint leaving GW Network failed: %v", sb.containerID, err)
8989
}
90-
if err := ep.Delete(); err != nil {
90+
if err := ep.Delete(false); err != nil {
9191
return fmt.Errorf("container %s: deleting endpoint on GW Network failed: %v", sb.containerID, err)
9292
}
9393
return nil

endpoint.go

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -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
}

libnetwork_internal_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ func TestIpamReleaseOnNetDriverFailures(t *testing.T) {
407407
if err != nil {
408408
t.Fatal(err)
409409
}
410-
defer ep.Delete()
410+
defer ep.Delete(false)
411411

412412
expectedIP, _ := types.ParseCIDR("10.34.0.1/16")
413413
if !types.CompareIPNet(ep.Info().Iface().Address(), expectedIP) {

0 commit comments

Comments
 (0)