@@ -451,24 +451,16 @@ func (mgr *ContainerManager) Start(ctx context.Context, id, detachKeys string) (
451451
452452func (mgr * ContainerManager ) start (ctx context.Context , c * Container , detachKeys string ) error {
453453 var err error
454-
455- c .Lock ()
456- if c .Config == nil || c .State == nil {
457- c .Unlock ()
458- return errors .Wrapf (errtypes .ErrNotfound , "container %s" , c .ID )
459- }
460454 c .DetachKeys = detachKeys
461455
462- // attach volume
463456 attachedVolumes := map [string ]struct {}{}
464457 defer func () {
465- if err != nil {
466- for name := range attachedVolumes {
467- _ , err = mgr .VolumeMgr .Detach (ctx , name , map [string ]string {volumetypes .OptionRef : c .ID })
468- if err != nil {
469- logrus .Errorf ("failed to detach volume(%s) when start container(%s) rollback" ,
470- name , c .ID )
471- }
458+ if err == nil {
459+ return
460+ }
461+ for name := range attachedVolumes {
462+ if _ , err = mgr .VolumeMgr .Detach (ctx , name , map [string ]string {volumetypes .OptionRef : c .ID }); err != nil {
463+ logrus .Errorf ("failed to detach volume(%s) when start container(%s) rollback: %v" , name , c .ID , err )
472464 }
473465 }
474466 }()
@@ -477,23 +469,33 @@ func (mgr *ContainerManager) start(ctx context.Context, c *Container, detachKeys
477469 if mp .Name == "" {
478470 continue
479471 }
480-
481- _ , err = mgr .VolumeMgr .Attach (ctx , mp .Name , map [string ]string {volumetypes .OptionRef : c .ID })
482- if err != nil {
483- c .Unlock ()
472+ if _ , err = mgr .VolumeMgr .Attach (ctx , mp .Name , map [string ]string {volumetypes .OptionRef : c .ID }); err != nil {
484473 return errors .Wrapf (err , "failed to attach volume(%s)" , mp .Name )
485474 }
486475 attachedVolumes [mp .Name ] = struct {}{}
487476 }
488477
489- // initialise container network mode
478+ if err = mgr .prepareContainerNetwork (ctx , c ); err != nil {
479+ return err
480+ }
481+
482+ if err = mgr .createContainerdContainer (ctx , c ); err != nil {
483+ return errors .Wrapf (err , "failed to create container(%s) on containerd" , c .ID )
484+ }
485+
486+ return nil
487+ }
488+
489+ func (mgr * ContainerManager ) prepareContainerNetwork (ctx context.Context , c * Container ) error {
490+ c .Lock ()
491+ defer c .Unlock ()
492+
490493 networkMode := c .HostConfig .NetworkMode
491494
492495 if IsContainer (networkMode ) {
493496 var origContainer * Container
494- origContainer , err = mgr .Get (ctx , strings .SplitN (networkMode , ":" , 2 )[1 ])
497+ origContainer , err : = mgr .Get (ctx , strings .SplitN (networkMode , ":" , 2 )[1 ])
495498 if err != nil {
496- c .Unlock ()
497499 return err
498500 }
499501
@@ -502,42 +504,37 @@ func (mgr *ContainerManager) start(ctx context.Context, c *Container, detachKeys
502504 c .ResolvConfPath = origContainer .ResolvConfPath
503505 c .Config .Hostname = origContainer .Config .Hostname
504506 c .Config .Domainname = origContainer .Config .Domainname
505- } else {
506- // initialise host network mode
507- if IsHost (networkMode ) {
508- var hostname string
509- hostname , err = os .Hostname ()
510- if err != nil {
511- c .Unlock ()
512- return err
513- }
514- c .Config .Hostname = strfmt .Hostname (hostname )
515- }
516507
517- // build the network related path.
518- if err = mgr .buildNetworkRelatedPath (c ); err != nil {
519- c .Unlock ()
508+ return nil
509+ }
510+
511+ // initialise host network mode
512+ if IsHost (networkMode ) {
513+ hostname , err := os .Hostname ()
514+ if err != nil {
520515 return err
521516 }
517+ c .Config .Hostname = strfmt .Hostname (hostname )
518+ }
522519
523- // initialise network endpoint
524- if c .NetworkSettings != nil {
525- for name , endpointSetting := range c .NetworkSettings .Networks {
526- endpoint := mgr .buildContainerEndpoint (c )
527- endpoint .Name = name
528- endpoint .EndpointConfig = endpointSetting
529- if _ , err = mgr .NetworkMgr .EndpointCreate (ctx , endpoint ); err != nil {
530- logrus .Errorf ("failed to create endpoint: %v" , err )
531- c .Unlock ()
532- return err
533- }
534- }
535- }
520+ // build the network related path.
521+ if err := mgr .buildNetworkRelatedPath (c ); err != nil {
522+ return err
536523 }
537- c .Unlock ()
538524
539- if err = mgr .createContainerdContainer (ctx , c ); err != nil {
540- return errors .Wrapf (err , "failed to create container(%s) on containerd" , c .ID )
525+ // initialise network endpoint
526+ if c .NetworkSettings == nil {
527+ return nil
528+ }
529+
530+ for name , endpointSetting := range c .NetworkSettings .Networks {
531+ endpoint := mgr .buildContainerEndpoint (c )
532+ endpoint .Name = name
533+ endpoint .EndpointConfig = endpointSetting
534+ if _ , err := mgr .NetworkMgr .EndpointCreate (ctx , endpoint ); err != nil {
535+ logrus .Errorf ("failed to create endpoint: %v" , err )
536+ return err
537+ }
541538 }
542539
543540 return nil
@@ -937,35 +934,38 @@ func (mgr *ContainerManager) Remove(ctx context.Context, name string, options *t
937934
938935 // if the container is running, force to stop it.
939936 if c .IsRunning () && options .Force {
940- msg , err := mgr .Client .DestroyContainer (ctx , c .ID , c .StopTimeout ())
937+ _ , err := mgr .Client .DestroyContainer (ctx , c .ID , c .StopTimeout ())
941938 if err != nil && ! errtypes .IsNotfound (err ) {
942- return errors .Wrapf (err , "failed to destroy container %s" , c .ID )
939+ return errors .Wrapf (err , "failed to destroy container %s when removing " , c .ID )
943940 }
944- if err := mgr .markStoppedAndRelease (c , msg ); err != nil {
945- return errors .Wrapf (err , "failed to mark container %s stop status" , c .ID )
941+ // After stopping a running container, we should release container resource
942+ c .UnsetMergedDir ()
943+ if err := mgr .releaseContainerResources (c ); err != nil {
944+ logrus .Errorf ("failed to release container %s resources when removing: %v" , c .ID , err )
946945 }
947946 }
948947
949948 if err := mgr .detachVolumes (ctx , c , options .Volumes ); err != nil {
950949 logrus .Errorf ("failed to detach volume: %v" , err )
951950 }
952951
953- // remove name
954- c .Lock ()
955- mgr .NameToID .Remove (c .Name )
956- c .Unlock ()
957-
958- // remove meta data
959- if err := mgr .Store .Remove (c .Key ()); err != nil {
960- logrus .Errorf ("failed to remove container %s from meta store: %v" , c .ID , err )
952+ // remove snapshot
953+ if err := mgr .Client .RemoveSnapshot (ctx , c .ID ); err != nil {
954+ logrus .Errorf ("failed to remove snapshot of container %s: %v" , c .ID , err )
961955 }
962956
957+ // When removing a container, we have set up such rule for object removing sequences:
958+ // 1. container object in pouchd's memory;
959+ // 2. meta.json for container in local disk.
960+
961+ // remove name
962+ mgr .NameToID .Remove (c .Name )
963963 // remove container cache
964964 mgr .cache .Remove (c .ID )
965965
966- // remove snapshot
967- if err := mgr .Client . RemoveSnapshot ( ctx , c . ID ); err != nil {
968- logrus .Errorf ("failed to remove snapshot of container %s: %v" , c .ID , err )
966+ // remove meta.json for container in local disk
967+ if err := mgr .Store . Remove ( c . Key () ); err != nil {
968+ logrus .Errorf ("failed to remove container %s from meta store : %v" , c .ID , err )
969969 }
970970
971971 return nil
@@ -1718,14 +1718,6 @@ func (mgr *ContainerManager) markStoppedAndRelease(c *Container, m *ctrd.Message
17181718
17191719 c .SetStatusStopped (code , errMsg )
17201720
1721- // unset Snapshot MergedDir. Stop a container will
1722- // delete the containerd container, the merged dir
1723- // will also be deleted, so we should unset the
1724- // container's MergedDir.
1725- if c .Snapshotter != nil && c .Snapshotter .Data != nil {
1726- c .Snapshotter .Data ["MergedDir" ] = ""
1727- }
1728-
17291721 // Action Container Remove and function markStoppedAndRelease are conflict.
17301722 // If a container has been removed and the corresponding meta.json will be removed as well.
17311723 // However, when this function markStoppedAndRelease still keeps the container instance,
@@ -1738,47 +1730,52 @@ func (mgr *ContainerManager) markStoppedAndRelease(c *Container, m *ctrd.Message
17381730
17391731 // Remove io and network config may occur error, so we should update
17401732 // container's status on disk as soon as possible.
1741- if err := c .Write (mgr .Store ); err != nil {
1742- logrus .Errorf ("failed to update meta: %v" , err )
1743- return err
1744- }
1733+ defer func () {
1734+ if err := c .Write (mgr .Store ); err != nil {
1735+ logrus .Errorf ("failed to update meta: %v" , err )
1736+ }
1737+ }()
17451738
1746- // release resource
1747- if io := mgr .IOs .Get (c .ID ); io != nil {
1748- io .Close ()
1749- mgr .IOs .Remove (c .ID )
1739+ c .UnsetMergedDir ()
1740+
1741+ return mgr .releaseContainerResources (c )
1742+ }
1743+
1744+ func (mgr * ContainerManager ) markExitedAndRelease (c * Container , m * ctrd.Message ) error {
1745+ var (
1746+ exitCode int64 // container exit code used for container state setting
1747+ errMsg string // container exit error message used for container state setting
1748+ )
1749+ if m != nil {
1750+ exitCode = int64 (m .ExitCode ())
1751+ if err := m .RawError (); err != nil {
1752+ errMsg = err .Error ()
1753+ }
17501754 }
17511755
1752- // No network binded, just return
1753- c .Lock ()
1754- if c .NetworkSettings == nil {
1755- c .Unlock ()
1756+ c .SetStatusExited (exitCode , errMsg )
1757+
1758+ // Action Container Remove and function markStoppedAndRelease are conflict.
1759+ // If a container has been removed and the corresponding meta.json will be removed as well.
1760+ // However, when this function markStoppedAndRelease still keeps the container instance,
1761+ // there will be possibility that in markStoppedAndRelease, code calls c.Write(mgr.Store) to
1762+ // write the removed meta.json again. If that, incompatibilty happens.
1763+ // As a result, we check whether this container is still in the meta store.
1764+ if container , err := mgr .container (c .Name ); err != nil || container == nil {
17561765 return nil
17571766 }
17581767
1759- for name , epConfig := range c .NetworkSettings .Networks {
1760- endpoint := mgr .buildContainerEndpoint (c )
1761- endpoint .Name = name
1762- endpoint .EndpointConfig = epConfig
1763- if err := mgr .NetworkMgr .EndpointRemove (context .Background (), endpoint ); err != nil {
1764- // TODO(ziren): it is a trick, we should wrapper "sanbox
1765- // not found"" as an error type
1766- if ! strings .Contains (err .Error (), "not found" ) {
1767- logrus .Errorf ("failed to remove endpoint: %v" , err )
1768- c .Unlock ()
1769- return err
1770- }
1768+ // Remove io and network config may occur error, so we should update
1769+ // container's status on disk as soon as possible.
1770+ defer func () {
1771+ if err := c .Write (mgr .Store ); err != nil {
1772+ logrus .Errorf ("failed to update meta: %v" , err )
17711773 }
1772- }
1773- c .Unlock ()
1774+ }()
17741775
1775- // update meta
1776- if err := c .Write (mgr .Store ); err != nil {
1777- logrus .Errorf ("failed to update meta of container %s: %v" , c .ID , err )
1778- return err
1779- }
1776+ c .UnsetMergedDir ()
17801777
1781- return nil
1778+ return mgr . releaseContainerResources ( c )
17821779}
17831780
17841781// exitedAndRelease be register into ctrd as a callback function, when the running container suddenly
@@ -1789,12 +1786,10 @@ func (mgr *ContainerManager) exitedAndRelease(id string, m *ctrd.Message) error
17891786 return err
17901787 }
17911788
1792- if err := mgr .markStoppedAndRelease (c , m ); err != nil {
1789+ if err := mgr .markExitedAndRelease (c , m ); err != nil {
17931790 return err
17941791 }
17951792
1796- c .SetStatusExited ()
1797-
17981793 // Action Container Remove and function exitedAndRelease are conflict.
17991794 // If a container has been removed and the corresponding meta.json will be removed as well.
18001795 // However, when this function exitedAndRelease still keeps the container instance,
@@ -1805,11 +1800,6 @@ func (mgr *ContainerManager) exitedAndRelease(id string, m *ctrd.Message) error
18051800 return nil
18061801 }
18071802
1808- if err := c .Write (mgr .Store ); err != nil {
1809- logrus .Errorf ("failed to update meta: %v" , err )
1810- return err
1811- }
1812-
18131803 // send exit event to monitor
18141804 mgr .monitor .PostEvent (ContainerExitEvent (c ).WithHandle (func (c * Container ) error {
18151805 // check status and restart policy
@@ -1847,19 +1837,65 @@ func (mgr *ContainerManager) execExitedAndRelease(id string, m *ctrd.Message) er
18471837 execConfig .Running = false
18481838 execConfig .Error = m .RawError ()
18491839
1850- if io := mgr .IOs .Get (id ); io != nil {
1851- if err := m .RawError (); err != nil {
1852- fmt .Fprintf (io .Stdout , "%v\n " , err )
1853- }
1840+ io := mgr .IOs .Get (id )
1841+ if io == nil {
1842+ return nil
1843+ }
1844+
1845+ if err := m .RawError (); err != nil {
1846+ fmt .Fprintf (io .Stdout , "%v\n " , err )
1847+ }
1848+
1849+ // close io
1850+ io .Close ()
1851+ mgr .IOs .Remove (id )
1852+
1853+ return nil
1854+ }
1855+
1856+ func (mgr * ContainerManager ) releaseContainerResources (c * Container ) error {
1857+ mgr .releaseContainerIOs (c .ID )
1858+ return mgr .releaseContainerNetwork (c )
1859+ }
1860+
1861+ // releaseContainerNetwork release container network when container exits or is stopped.
1862+ func (mgr * ContainerManager ) releaseContainerNetwork (c * Container ) error {
1863+ c .Lock ()
1864+ defer c .Unlock ()
1865+ if c .NetworkSettings == nil {
1866+ return nil
1867+ }
18541868
1855- // close io
1856- io .Close ()
1857- mgr .IOs .Remove (id )
1869+ for name , epConfig := range c .NetworkSettings .Networks {
1870+ endpoint := mgr .buildContainerEndpoint (c )
1871+ endpoint .Name = name
1872+ endpoint .EndpointConfig = epConfig
1873+ if err := mgr .NetworkMgr .EndpointRemove (context .Background (), endpoint ); err != nil {
1874+ // TODO(ziren): it is a trick, we should wrapper "sanbox
1875+ // not found"" as an error type
1876+ if ! strings .Contains (err .Error (), "not found" ) {
1877+ logrus .Errorf ("failed to remove endpoint: %v" , err )
1878+ return err
1879+ }
1880+ }
18581881 }
18591882
18601883 return nil
18611884}
18621885
1886+ // releaseContainerIOs releases container IO resources.
1887+ func (mgr * ContainerManager ) releaseContainerIOs (containerID string ) {
1888+ // release resource
1889+ io := mgr .IOs .Get (containerID )
1890+ if io == nil {
1891+ return
1892+ }
1893+
1894+ io .Close ()
1895+ mgr .IOs .Remove (containerID )
1896+ return
1897+ }
1898+
18631899func (mgr * ContainerManager ) attachVolume (ctx context.Context , name string , c * Container ) (string , string , error ) {
18641900 driver := volumetypes .DefaultBackend
18651901 v , err := mgr .VolumeMgr .Get (ctx , name )
0 commit comments