github.com/moby/docker@v26.1.3+incompatible/libnetwork/sandbox_store.go (about)

     1  package libnetwork
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"sync"
     8  
     9  	"github.com/containerd/log"
    10  	"github.com/docker/docker/libnetwork/datastore"
    11  	"github.com/docker/docker/libnetwork/osl"
    12  	"github.com/docker/docker/libnetwork/scope"
    13  )
    14  
    15  const (
    16  	sandboxPrefix = "sandbox"
    17  )
    18  
    19  type epState struct {
    20  	Eid string
    21  	Nid string
    22  }
    23  
    24  type sbState struct {
    25  	ID         string
    26  	Cid        string
    27  	c          *Controller
    28  	dbIndex    uint64
    29  	dbExists   bool
    30  	Eps        []epState
    31  	EpPriority map[string]int
    32  	// external servers have to be persisted so that on restart of a live-restore
    33  	// enabled daemon we get the external servers for the running containers.
    34  	//
    35  	// It is persisted as "ExtDNS2" for historical reasons. ExtDNS2 was used to
    36  	// handle migration between docker < 1.14 and >= 1.14. Before version 1.14 we
    37  	// used ExtDNS but with a []string. As it's unlikely that installations still
    38  	// have state from before 1.14, we've dropped the migration code.
    39  	ExtDNS []extDNSEntry `json:"ExtDNS2"`
    40  }
    41  
    42  func (sbs *sbState) Key() []string {
    43  	return []string{sandboxPrefix, sbs.ID}
    44  }
    45  
    46  func (sbs *sbState) KeyPrefix() []string {
    47  	return []string{sandboxPrefix}
    48  }
    49  
    50  func (sbs *sbState) Value() []byte {
    51  	b, err := json.Marshal(sbs)
    52  	if err != nil {
    53  		return nil
    54  	}
    55  	return b
    56  }
    57  
    58  func (sbs *sbState) SetValue(value []byte) error {
    59  	return json.Unmarshal(value, sbs)
    60  }
    61  
    62  func (sbs *sbState) Index() uint64 {
    63  	sb, err := sbs.c.SandboxByID(sbs.ID)
    64  	if err != nil {
    65  		return sbs.dbIndex
    66  	}
    67  
    68  	maxIndex := sb.dbIndex
    69  	if sbs.dbIndex > maxIndex {
    70  		maxIndex = sbs.dbIndex
    71  	}
    72  
    73  	return maxIndex
    74  }
    75  
    76  func (sbs *sbState) SetIndex(index uint64) {
    77  	sbs.dbIndex = index
    78  	sbs.dbExists = true
    79  
    80  	sb, err := sbs.c.SandboxByID(sbs.ID)
    81  	if err != nil {
    82  		return
    83  	}
    84  
    85  	sb.dbIndex = index
    86  	sb.dbExists = true
    87  }
    88  
    89  func (sbs *sbState) Exists() bool {
    90  	if sbs.dbExists {
    91  		return sbs.dbExists
    92  	}
    93  
    94  	sb, err := sbs.c.SandboxByID(sbs.ID)
    95  	if err != nil {
    96  		return false
    97  	}
    98  
    99  	return sb.dbExists
   100  }
   101  
   102  func (sbs *sbState) Skip() bool {
   103  	return false
   104  }
   105  
   106  func (sbs *sbState) New() datastore.KVObject {
   107  	return &sbState{c: sbs.c}
   108  }
   109  
   110  func (sbs *sbState) CopyTo(o datastore.KVObject) error {
   111  	dstSbs := o.(*sbState)
   112  	dstSbs.c = sbs.c
   113  	dstSbs.ID = sbs.ID
   114  	dstSbs.Cid = sbs.Cid
   115  	dstSbs.dbIndex = sbs.dbIndex
   116  	dstSbs.dbExists = sbs.dbExists
   117  	dstSbs.EpPriority = sbs.EpPriority
   118  
   119  	dstSbs.Eps = append(dstSbs.Eps, sbs.Eps...)
   120  	dstSbs.ExtDNS = append(dstSbs.ExtDNS, sbs.ExtDNS...)
   121  
   122  	return nil
   123  }
   124  
   125  func (sb *Sandbox) storeUpdate() error {
   126  	sbs := &sbState{
   127  		c:          sb.controller,
   128  		ID:         sb.id,
   129  		Cid:        sb.containerID,
   130  		EpPriority: sb.epPriority,
   131  		ExtDNS:     sb.extDNS,
   132  	}
   133  
   134  retry:
   135  	sbs.Eps = nil
   136  	for _, ep := range sb.Endpoints() {
   137  		// If the endpoint is not persisted then do not add it to
   138  		// the sandbox checkpoint
   139  		if ep.Skip() {
   140  			continue
   141  		}
   142  
   143  		sbs.Eps = append(sbs.Eps, epState{
   144  			Nid: ep.getNetwork().ID(),
   145  			Eid: ep.ID(),
   146  		})
   147  	}
   148  
   149  	err := sb.controller.updateToStore(sbs)
   150  	if err == datastore.ErrKeyModified {
   151  		// When we get ErrKeyModified it is sufficient to just
   152  		// go back and retry.  No need to get the object from
   153  		// the store because we always regenerate the store
   154  		// state from in memory sandbox state
   155  		goto retry
   156  	}
   157  
   158  	return err
   159  }
   160  
   161  func (sb *Sandbox) storeDelete() error {
   162  	cs := sb.controller.getStore()
   163  	if cs == nil {
   164  		return fmt.Errorf("datastore is not initialized")
   165  	}
   166  
   167  	return cs.DeleteObject(&sbState{
   168  		c:        sb.controller,
   169  		ID:       sb.id,
   170  		Cid:      sb.containerID,
   171  		dbExists: sb.dbExists,
   172  	})
   173  }
   174  
   175  func (c *Controller) sandboxCleanup(activeSandboxes map[string]interface{}) error {
   176  	store := c.getStore()
   177  	if store == nil {
   178  		return fmt.Errorf("could not find local scope store")
   179  	}
   180  
   181  	sandboxStates, err := store.List(&sbState{c: c})
   182  	if err != nil {
   183  		if err == datastore.ErrKeyNotFound {
   184  			// It's normal for no sandboxes to be found. Just bail out.
   185  			return nil
   186  		}
   187  		return fmt.Errorf("failed to get sandboxes: %v", err)
   188  	}
   189  
   190  	for _, s := range sandboxStates {
   191  		sbs := s.(*sbState)
   192  		sb := &Sandbox{
   193  			id:                 sbs.ID,
   194  			controller:         sbs.c,
   195  			containerID:        sbs.Cid,
   196  			extDNS:             sbs.ExtDNS,
   197  			endpoints:          []*Endpoint{},
   198  			populatedEndpoints: map[string]struct{}{},
   199  			dbIndex:            sbs.dbIndex,
   200  			isStub:             true,
   201  			dbExists:           true,
   202  		}
   203  
   204  		msg := " for cleanup"
   205  		create := true
   206  		isRestore := false
   207  		if val, ok := activeSandboxes[sb.ID()]; ok {
   208  			msg = ""
   209  			sb.isStub = false
   210  			isRestore = true
   211  			opts := val.([]SandboxOption)
   212  			sb.processOptions(opts...)
   213  			sb.restoreHostsPath()
   214  			sb.restoreResolvConfPath()
   215  			create = !sb.config.useDefaultSandBox
   216  		}
   217  		sb.osSbox, err = osl.NewSandbox(sb.Key(), create, isRestore)
   218  		if err != nil {
   219  			log.G(context.TODO()).Errorf("failed to create osl sandbox while trying to restore sandbox %.7s%s: %v", sb.ID(), msg, err)
   220  			continue
   221  		}
   222  
   223  		c.mu.Lock()
   224  		c.sandboxes[sb.id] = sb
   225  		c.mu.Unlock()
   226  
   227  		for _, eps := range sbs.Eps {
   228  			n, err := c.getNetworkFromStore(eps.Nid)
   229  			var ep *Endpoint
   230  			if err != nil {
   231  				log.G(context.TODO()).Errorf("getNetworkFromStore for nid %s failed while trying to build sandbox for cleanup: %v", eps.Nid, err)
   232  				ep = &Endpoint{
   233  					id: eps.Eid,
   234  					network: &Network{
   235  						id:      eps.Nid,
   236  						ctrlr:   c,
   237  						drvOnce: &sync.Once{},
   238  						persist: true,
   239  					},
   240  					sandboxID: sbs.ID,
   241  				}
   242  			} else {
   243  				ep, err = n.getEndpointFromStore(eps.Eid)
   244  				if err != nil {
   245  					log.G(context.TODO()).Errorf("getEndpointFromStore for eid %s failed while trying to build sandbox for cleanup: %v", eps.Eid, err)
   246  					ep = &Endpoint{
   247  						id:        eps.Eid,
   248  						network:   n,
   249  						sandboxID: sbs.ID,
   250  					}
   251  				}
   252  			}
   253  			if _, ok := activeSandboxes[sb.ID()]; ok && err != nil {
   254  				log.G(context.TODO()).Errorf("failed to restore endpoint %s in %s for container %s due to %v", eps.Eid, eps.Nid, sb.ContainerID(), err)
   255  				continue
   256  			}
   257  			sb.addEndpoint(ep)
   258  		}
   259  
   260  		if _, ok := activeSandboxes[sb.ID()]; !ok {
   261  			log.G(context.TODO()).Infof("Removing stale sandbox %s (%s)", sb.id, sb.containerID)
   262  			if err := sb.delete(true); err != nil {
   263  				log.G(context.TODO()).Errorf("Failed to delete sandbox %s while trying to cleanup: %v", sb.id, err)
   264  			}
   265  			continue
   266  		}
   267  
   268  		// reconstruct osl sandbox field
   269  		if !sb.config.useDefaultSandBox {
   270  			if err := sb.restoreOslSandbox(); err != nil {
   271  				log.G(context.TODO()).Errorf("failed to populate fields for osl sandbox %s: %v", sb.ID(), err)
   272  				continue
   273  			}
   274  		} else {
   275  			// FIXME(thaJeztah): osSbox (and thus defOsSbox) is always nil on non-Linux: move this code to Linux-only files.
   276  			c.defOsSboxOnce.Do(func() {
   277  				c.defOsSbox = sb.osSbox
   278  			})
   279  		}
   280  
   281  		for _, ep := range sb.endpoints {
   282  			if !c.isAgent() {
   283  				n := ep.getNetwork()
   284  				if !c.isSwarmNode() || n.Scope() != scope.Swarm || !n.driverIsMultihost() {
   285  					n.updateSvcRecord(ep, true)
   286  				}
   287  			}
   288  		}
   289  	}
   290  
   291  	return nil
   292  }