container_operations.go 35 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154
  1. package daemon // import "github.com/docker/docker/daemon"
  2. import (
  3. "context"
  4. "errors"
  5. "fmt"
  6. "net"
  7. "os"
  8. "path"
  9. "strings"
  10. "time"
  11. "github.com/containerd/log"
  12. containertypes "github.com/docker/docker/api/types/container"
  13. "github.com/docker/docker/api/types/events"
  14. networktypes "github.com/docker/docker/api/types/network"
  15. "github.com/docker/docker/container"
  16. "github.com/docker/docker/daemon/config"
  17. "github.com/docker/docker/daemon/network"
  18. "github.com/docker/docker/errdefs"
  19. "github.com/docker/docker/internal/multierror"
  20. "github.com/docker/docker/libnetwork"
  21. "github.com/docker/docker/libnetwork/netlabel"
  22. "github.com/docker/docker/libnetwork/options"
  23. "github.com/docker/docker/libnetwork/scope"
  24. "github.com/docker/docker/libnetwork/types"
  25. "github.com/docker/docker/opts"
  26. "github.com/docker/docker/pkg/stringid"
  27. "github.com/docker/docker/runconfig"
  28. "github.com/docker/go-connections/nat"
  29. )
  30. func ipAddresses(ips []net.IP) []string {
  31. var addrs []string
  32. for _, ip := range ips {
  33. addrs = append(addrs, ip.String())
  34. }
  35. return addrs
  36. }
  37. func (daemon *Daemon) buildSandboxOptions(cfg *config.Config, container *container.Container) ([]libnetwork.SandboxOption, error) {
  38. var sboxOptions []libnetwork.SandboxOption
  39. sboxOptions = append(sboxOptions, libnetwork.OptionHostname(container.Config.Hostname), libnetwork.OptionDomainname(container.Config.Domainname))
  40. if container.HostConfig.NetworkMode.IsHost() {
  41. sboxOptions = append(sboxOptions, libnetwork.OptionUseDefaultSandbox())
  42. } else {
  43. // OptionUseExternalKey is mandatory for userns support.
  44. // But optional for non-userns support
  45. sboxOptions = append(sboxOptions, libnetwork.OptionUseExternalKey())
  46. }
  47. if err := setupPathsAndSandboxOptions(container, cfg, &sboxOptions); err != nil {
  48. return nil, err
  49. }
  50. if len(container.HostConfig.DNS) > 0 {
  51. sboxOptions = append(sboxOptions, libnetwork.OptionDNS(container.HostConfig.DNS))
  52. } else if len(cfg.DNS) > 0 {
  53. sboxOptions = append(sboxOptions, libnetwork.OptionDNS(ipAddresses(cfg.DNS)))
  54. }
  55. if len(container.HostConfig.DNSSearch) > 0 {
  56. sboxOptions = append(sboxOptions, libnetwork.OptionDNSSearch(container.HostConfig.DNSSearch))
  57. } else if len(cfg.DNSSearch) > 0 {
  58. sboxOptions = append(sboxOptions, libnetwork.OptionDNSSearch(cfg.DNSSearch))
  59. }
  60. if len(container.HostConfig.DNSOptions) > 0 {
  61. sboxOptions = append(sboxOptions, libnetwork.OptionDNSOptions(container.HostConfig.DNSOptions))
  62. } else if len(cfg.DNSOptions) > 0 {
  63. sboxOptions = append(sboxOptions, libnetwork.OptionDNSOptions(cfg.DNSOptions))
  64. }
  65. if container.NetworkSettings.SecondaryIPAddresses != nil {
  66. name := container.Config.Hostname
  67. if container.Config.Domainname != "" {
  68. name = name + "." + container.Config.Domainname
  69. }
  70. for _, a := range container.NetworkSettings.SecondaryIPAddresses {
  71. sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(name, a.Addr))
  72. }
  73. }
  74. for _, extraHost := range container.HostConfig.ExtraHosts {
  75. // allow IPv6 addresses in extra hosts; only split on first ":"
  76. if _, err := opts.ValidateExtraHost(extraHost); err != nil {
  77. return nil, err
  78. }
  79. host, ip, _ := strings.Cut(extraHost, ":")
  80. // If the IP Address is a string called "host-gateway", replace this
  81. // value with the IP address stored in the daemon level HostGatewayIP
  82. // config variable
  83. if ip == opts.HostGatewayName {
  84. gateway := cfg.HostGatewayIP.String()
  85. if gateway == "" {
  86. return nil, fmt.Errorf("unable to derive the IP value for host-gateway")
  87. }
  88. ip = gateway
  89. }
  90. sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(host, ip))
  91. }
  92. bindings := make(nat.PortMap)
  93. if container.HostConfig.PortBindings != nil {
  94. for p, b := range container.HostConfig.PortBindings {
  95. bindings[p] = []nat.PortBinding{}
  96. for _, bb := range b {
  97. bindings[p] = append(bindings[p], nat.PortBinding{
  98. HostIP: bb.HostIP,
  99. HostPort: bb.HostPort,
  100. })
  101. }
  102. }
  103. }
  104. // TODO(thaJeztah): Move this code to a method on nat.PortSet.
  105. ports := make([]nat.Port, 0, len(container.Config.ExposedPorts))
  106. for p := range container.Config.ExposedPorts {
  107. ports = append(ports, p)
  108. }
  109. nat.SortPortMap(ports, bindings)
  110. var (
  111. publishedPorts []types.PortBinding
  112. exposedPorts []types.TransportPort
  113. )
  114. for _, port := range ports {
  115. portProto := types.ParseProtocol(port.Proto())
  116. portNum := uint16(port.Int())
  117. exposedPorts = append(exposedPorts, types.TransportPort{
  118. Proto: portProto,
  119. Port: portNum,
  120. })
  121. for _, binding := range bindings[port] {
  122. newP, err := nat.NewPort(nat.SplitProtoPort(binding.HostPort))
  123. var portStart, portEnd int
  124. if err == nil {
  125. portStart, portEnd, err = newP.Range()
  126. }
  127. if err != nil {
  128. return nil, fmt.Errorf("Error parsing HostPort value(%s):%v", binding.HostPort, err)
  129. }
  130. publishedPorts = append(publishedPorts, types.PortBinding{
  131. Proto: portProto,
  132. Port: portNum,
  133. HostIP: net.ParseIP(binding.HostIP),
  134. HostPort: uint16(portStart),
  135. HostPortEnd: uint16(portEnd),
  136. })
  137. }
  138. if container.HostConfig.PublishAllPorts && len(bindings[port]) == 0 {
  139. publishedPorts = append(publishedPorts, types.PortBinding{
  140. Proto: portProto,
  141. Port: portNum,
  142. })
  143. }
  144. }
  145. sboxOptions = append(sboxOptions, libnetwork.OptionPortMapping(publishedPorts), libnetwork.OptionExposedPorts(exposedPorts))
  146. // Legacy Link feature is supported only for the default bridge network.
  147. // return if this call to build join options is not for default bridge network
  148. // Legacy Link is only supported by docker run --link
  149. defaultNetName := runconfig.DefaultDaemonNetworkMode().NetworkName()
  150. bridgeSettings, ok := container.NetworkSettings.Networks[defaultNetName]
  151. if !ok || bridgeSettings.EndpointSettings == nil || bridgeSettings.EndpointID == "" {
  152. return sboxOptions, nil
  153. }
  154. var (
  155. childEndpoints []string
  156. cEndpointID string
  157. )
  158. for linkAlias, child := range daemon.children(container) {
  159. if !isLinkable(child) {
  160. return nil, fmt.Errorf("Cannot link to %s, as it does not belong to the default network", child.Name)
  161. }
  162. _, alias := path.Split(linkAlias)
  163. // allow access to the linked container via the alias, real name, and container hostname
  164. aliasList := alias + " " + child.Config.Hostname
  165. // only add the name if alias isn't equal to the name
  166. if alias != child.Name[1:] {
  167. aliasList = aliasList + " " + child.Name[1:]
  168. }
  169. defaultNW := child.NetworkSettings.Networks[defaultNetName]
  170. if defaultNW.IPAddress != "" {
  171. sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(aliasList, defaultNW.IPAddress))
  172. }
  173. if defaultNW.GlobalIPv6Address != "" {
  174. sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(aliasList, defaultNW.GlobalIPv6Address))
  175. }
  176. cEndpointID = defaultNW.EndpointID
  177. if cEndpointID != "" {
  178. childEndpoints = append(childEndpoints, cEndpointID)
  179. }
  180. }
  181. var parentEndpoints []string
  182. for alias, parent := range daemon.parents(container) {
  183. if cfg.DisableBridge || !container.HostConfig.NetworkMode.IsPrivate() {
  184. continue
  185. }
  186. _, alias = path.Split(alias)
  187. log.G(context.TODO()).Debugf("Update /etc/hosts of %s for alias %s with ip %s", parent.ID, alias, bridgeSettings.IPAddress)
  188. sboxOptions = append(sboxOptions, libnetwork.OptionParentUpdate(parent.ID, alias, bridgeSettings.IPAddress))
  189. if cEndpointID != "" {
  190. parentEndpoints = append(parentEndpoints, cEndpointID)
  191. }
  192. }
  193. sboxOptions = append(sboxOptions, libnetwork.OptionGeneric(options.Generic{
  194. netlabel.GenericData: options.Generic{
  195. "ParentEndpoints": parentEndpoints,
  196. "ChildEndpoints": childEndpoints,
  197. },
  198. }))
  199. return sboxOptions, nil
  200. }
  201. func (daemon *Daemon) updateNetworkSettings(container *container.Container, n *libnetwork.Network, endpointConfig *networktypes.EndpointSettings) error {
  202. if container.NetworkSettings == nil {
  203. container.NetworkSettings = &network.Settings{}
  204. }
  205. if container.NetworkSettings.Networks == nil {
  206. container.NetworkSettings.Networks = make(map[string]*network.EndpointSettings)
  207. }
  208. if !container.HostConfig.NetworkMode.IsHost() && containertypes.NetworkMode(n.Type()).IsHost() {
  209. return runconfig.ErrConflictHostNetwork
  210. }
  211. for s, v := range container.NetworkSettings.Networks {
  212. sn, err := daemon.FindNetwork(getNetworkID(s, v.EndpointSettings))
  213. if err != nil {
  214. continue
  215. }
  216. if sn.Name() == n.Name() {
  217. // If the network scope is swarm, then this
  218. // is an attachable network, which may not
  219. // be locally available previously.
  220. // So always update.
  221. if n.Scope() == scope.Swarm {
  222. continue
  223. }
  224. // Avoid duplicate config
  225. return nil
  226. }
  227. if !containertypes.NetworkMode(sn.Type()).IsPrivate() ||
  228. !containertypes.NetworkMode(n.Type()).IsPrivate() {
  229. return runconfig.ErrConflictSharedNetwork
  230. }
  231. if containertypes.NetworkMode(sn.Name()).IsNone() ||
  232. containertypes.NetworkMode(n.Name()).IsNone() {
  233. return runconfig.ErrConflictNoNetwork
  234. }
  235. }
  236. container.NetworkSettings.Networks[n.Name()] = &network.EndpointSettings{
  237. EndpointSettings: endpointConfig,
  238. }
  239. return nil
  240. }
  241. func (daemon *Daemon) updateEndpointNetworkSettings(cfg *config.Config, container *container.Container, n *libnetwork.Network, ep *libnetwork.Endpoint) error {
  242. if err := buildEndpointInfo(container.NetworkSettings, n, ep); err != nil {
  243. return err
  244. }
  245. if container.HostConfig.NetworkMode == runconfig.DefaultDaemonNetworkMode() {
  246. container.NetworkSettings.Bridge = cfg.BridgeConfig.Iface
  247. }
  248. return nil
  249. }
  250. // UpdateNetwork is used to update the container's network (e.g. when linked containers
  251. // get removed/unlinked).
  252. func (daemon *Daemon) updateNetwork(cfg *config.Config, container *container.Container) error {
  253. var (
  254. start = time.Now()
  255. ctrl = daemon.netController
  256. sid = container.NetworkSettings.SandboxID
  257. )
  258. sb, err := ctrl.SandboxByID(sid)
  259. if err != nil {
  260. return fmt.Errorf("error locating sandbox id %s: %v", sid, err)
  261. }
  262. // Find if container is connected to the default bridge network
  263. var n *libnetwork.Network
  264. for name, v := range container.NetworkSettings.Networks {
  265. sn, err := daemon.FindNetwork(getNetworkID(name, v.EndpointSettings))
  266. if err != nil {
  267. continue
  268. }
  269. if sn.Name() == runconfig.DefaultDaemonNetworkMode().NetworkName() {
  270. n = sn
  271. break
  272. }
  273. }
  274. if n == nil {
  275. // Not connected to the default bridge network; Nothing to do
  276. return nil
  277. }
  278. sbOptions, err := daemon.buildSandboxOptions(cfg, container)
  279. if err != nil {
  280. return fmt.Errorf("Update network failed: %v", err)
  281. }
  282. if err := sb.Refresh(sbOptions...); err != nil {
  283. return fmt.Errorf("Update network failed: Failure in refresh sandbox %s: %v", sid, err)
  284. }
  285. networkActions.WithValues("update").UpdateSince(start)
  286. return nil
  287. }
  288. func (daemon *Daemon) findAndAttachNetwork(container *container.Container, idOrName string, epConfig *networktypes.EndpointSettings) (*libnetwork.Network, *networktypes.NetworkingConfig, error) {
  289. id := getNetworkID(idOrName, epConfig)
  290. n, err := daemon.FindNetwork(id)
  291. if err != nil {
  292. // We should always be able to find the network for a managed container.
  293. if container.Managed {
  294. return nil, nil, err
  295. }
  296. }
  297. // If we found a network and if it is not dynamically created
  298. // we should never attempt to attach to that network here.
  299. if n != nil {
  300. if container.Managed || !n.Dynamic() {
  301. return n, nil, nil
  302. }
  303. // Throw an error if the container is already attached to the network
  304. if container.NetworkSettings.Networks != nil {
  305. networkName := n.Name()
  306. containerName := strings.TrimPrefix(container.Name, "/")
  307. if nw, ok := container.NetworkSettings.Networks[networkName]; ok && nw.EndpointID != "" {
  308. err := fmt.Errorf("%s is already attached to network %s", containerName, networkName)
  309. return n, nil, errdefs.Conflict(err)
  310. }
  311. }
  312. }
  313. var addresses []string
  314. if epConfig != nil && epConfig.IPAMConfig != nil {
  315. if epConfig.IPAMConfig.IPv4Address != "" {
  316. addresses = append(addresses, epConfig.IPAMConfig.IPv4Address)
  317. }
  318. if epConfig.IPAMConfig.IPv6Address != "" {
  319. addresses = append(addresses, epConfig.IPAMConfig.IPv6Address)
  320. }
  321. }
  322. if n == nil && daemon.attachableNetworkLock != nil {
  323. daemon.attachableNetworkLock.Lock(id)
  324. defer daemon.attachableNetworkLock.Unlock(id)
  325. }
  326. retryCount := 0
  327. var nwCfg *networktypes.NetworkingConfig
  328. for {
  329. // In all other cases, attempt to attach to the network to
  330. // trigger attachment in the swarm cluster manager.
  331. if daemon.clusterProvider != nil {
  332. var err error
  333. nwCfg, err = daemon.clusterProvider.AttachNetwork(id, container.ID, addresses)
  334. if err != nil {
  335. return nil, nil, err
  336. }
  337. }
  338. n, err = daemon.FindNetwork(id)
  339. if err != nil {
  340. if daemon.clusterProvider != nil {
  341. if err := daemon.clusterProvider.DetachNetwork(id, container.ID); err != nil {
  342. log.G(context.TODO()).Warnf("Could not rollback attachment for container %s to network %s: %v", container.ID, idOrName, err)
  343. }
  344. }
  345. // Retry network attach again if we failed to
  346. // find the network after successful
  347. // attachment because the only reason that
  348. // would happen is if some other container
  349. // attached to the swarm scope network went down
  350. // and removed the network while we were in
  351. // the process of attaching.
  352. if nwCfg != nil {
  353. if _, ok := err.(libnetwork.ErrNoSuchNetwork); ok {
  354. if retryCount >= 5 {
  355. return nil, nil, fmt.Errorf("could not find network %s after successful attachment", idOrName)
  356. }
  357. retryCount++
  358. continue
  359. }
  360. }
  361. return nil, nil, err
  362. }
  363. break
  364. }
  365. // This container has attachment to a swarm scope
  366. // network. Update the container network settings accordingly.
  367. container.NetworkSettings.HasSwarmEndpoint = true
  368. return n, nwCfg, nil
  369. }
  370. // updateContainerNetworkSettings updates the network settings
  371. func (daemon *Daemon) updateContainerNetworkSettings(container *container.Container, endpointsConfig map[string]*networktypes.EndpointSettings) {
  372. var n *libnetwork.Network
  373. mode := container.HostConfig.NetworkMode
  374. if container.Config.NetworkDisabled || mode.IsContainer() {
  375. return
  376. }
  377. networkName := mode.NetworkName()
  378. if mode.IsDefault() {
  379. networkName = daemon.netController.Config().DefaultNetwork
  380. }
  381. if mode.IsUserDefined() {
  382. var err error
  383. n, err = daemon.FindNetwork(networkName)
  384. if err == nil {
  385. networkName = n.Name()
  386. }
  387. }
  388. if container.NetworkSettings == nil {
  389. container.NetworkSettings = &network.Settings{}
  390. }
  391. if len(endpointsConfig) > 0 {
  392. if container.NetworkSettings.Networks == nil {
  393. container.NetworkSettings.Networks = make(map[string]*network.EndpointSettings)
  394. }
  395. for name, epConfig := range endpointsConfig {
  396. container.NetworkSettings.Networks[name] = &network.EndpointSettings{
  397. EndpointSettings: epConfig,
  398. }
  399. }
  400. }
  401. if container.NetworkSettings.Networks == nil {
  402. container.NetworkSettings.Networks = make(map[string]*network.EndpointSettings)
  403. container.NetworkSettings.Networks[networkName] = &network.EndpointSettings{
  404. EndpointSettings: &networktypes.EndpointSettings{},
  405. }
  406. }
  407. // Convert any settings added by client in default name to
  408. // engine's default network name key
  409. if mode.IsDefault() {
  410. if nConf, ok := container.NetworkSettings.Networks[mode.NetworkName()]; ok {
  411. container.NetworkSettings.Networks[networkName] = nConf
  412. delete(container.NetworkSettings.Networks, mode.NetworkName())
  413. }
  414. }
  415. if !mode.IsUserDefined() {
  416. return
  417. }
  418. // Make sure to internally store the per network endpoint config by network name
  419. if _, ok := container.NetworkSettings.Networks[networkName]; ok {
  420. return
  421. }
  422. if n != nil {
  423. if nwConfig, ok := container.NetworkSettings.Networks[n.ID()]; ok {
  424. container.NetworkSettings.Networks[networkName] = nwConfig
  425. delete(container.NetworkSettings.Networks, n.ID())
  426. return
  427. }
  428. }
  429. }
  430. func (daemon *Daemon) allocateNetwork(cfg *config.Config, container *container.Container) (retErr error) {
  431. if daemon.netController == nil {
  432. return nil
  433. }
  434. start := time.Now()
  435. // Cleanup any stale sandbox left over due to ungraceful daemon shutdown
  436. if err := daemon.netController.SandboxDestroy(container.ID); err != nil {
  437. log.G(context.TODO()).WithError(err).Errorf("failed to cleanup up stale network sandbox for container %s", container.ID)
  438. }
  439. if container.Config.NetworkDisabled || container.HostConfig.NetworkMode.IsContainer() {
  440. return nil
  441. }
  442. updateSettings := false
  443. if len(container.NetworkSettings.Networks) == 0 {
  444. daemon.updateContainerNetworkSettings(container, nil)
  445. updateSettings = true
  446. }
  447. // always connect default network first since only default
  448. // network mode support link and we need do some setting
  449. // on sandbox initialize for link, but the sandbox only be initialized
  450. // on first network connecting.
  451. defaultNetName := runconfig.DefaultDaemonNetworkMode().NetworkName()
  452. if nConf, ok := container.NetworkSettings.Networks[defaultNetName]; ok {
  453. cleanOperationalData(nConf)
  454. if err := daemon.connectToNetwork(cfg, container, defaultNetName, nConf.EndpointSettings, updateSettings); err != nil {
  455. return err
  456. }
  457. }
  458. // the intermediate map is necessary because "connectToNetwork" modifies "container.NetworkSettings.Networks"
  459. networks := make(map[string]*network.EndpointSettings)
  460. for n, epConf := range container.NetworkSettings.Networks {
  461. if n == defaultNetName {
  462. continue
  463. }
  464. networks[n] = epConf
  465. }
  466. for netName, epConf := range networks {
  467. cleanOperationalData(epConf)
  468. if err := daemon.connectToNetwork(cfg, container, netName, epConf.EndpointSettings, updateSettings); err != nil {
  469. return err
  470. }
  471. }
  472. // If the container is not to be connected to any network,
  473. // create its network sandbox now if not present
  474. if len(networks) == 0 {
  475. if _, err := daemon.netController.GetSandbox(container.ID); err != nil {
  476. if !errdefs.IsNotFound(err) {
  477. return err
  478. }
  479. sbOptions, err := daemon.buildSandboxOptions(cfg, container)
  480. if err != nil {
  481. return err
  482. }
  483. sb, err := daemon.netController.NewSandbox(container.ID, sbOptions...)
  484. if err != nil {
  485. return err
  486. }
  487. setNetworkSandbox(container, sb)
  488. defer func() {
  489. if retErr != nil {
  490. sb.Delete()
  491. }
  492. }()
  493. }
  494. }
  495. if _, err := container.WriteHostConfig(); err != nil {
  496. return err
  497. }
  498. networkActions.WithValues("allocate").UpdateSince(start)
  499. return nil
  500. }
  501. // validateEndpointSettings checks whether the given epConfig is valid. The nw parameter can be nil, in which case it
  502. // won't try to check if the endpoint IP addresses are within network's subnets.
  503. func validateEndpointSettings(nw *libnetwork.Network, nwName string, epConfig *networktypes.EndpointSettings) error {
  504. if epConfig == nil {
  505. return nil
  506. }
  507. ipamConfig := &networktypes.EndpointIPAMConfig{}
  508. if epConfig.IPAMConfig != nil {
  509. ipamConfig = epConfig.IPAMConfig
  510. }
  511. var errs []error
  512. // TODO(aker): move this into api/types/network/endpoint.go once enableIPOnPredefinedNetwork and
  513. // serviceDiscoveryOnDefaultNetwork are removed.
  514. if !containertypes.NetworkMode(nwName).IsUserDefined() {
  515. hasStaticAddresses := ipamConfig.IPv4Address != "" || ipamConfig.IPv6Address != ""
  516. // On Linux, user specified IP address is accepted only by networks with user specified subnets.
  517. if hasStaticAddresses && !enableIPOnPredefinedNetwork() {
  518. errs = append(errs, runconfig.ErrUnsupportedNetworkAndIP)
  519. }
  520. if len(epConfig.Aliases) > 0 && !serviceDiscoveryOnDefaultNetwork() {
  521. errs = append(errs, runconfig.ErrUnsupportedNetworkAndAlias)
  522. }
  523. }
  524. // TODO(aker): add a proper multierror.Append
  525. if err := ipamConfig.Validate(); err != nil {
  526. errs = append(errs, err.(interface{ Unwrap() []error }).Unwrap()...)
  527. }
  528. if nw != nil {
  529. _, _, v4Configs, v6Configs := nw.IpamConfig()
  530. var nwIPv4Subnets, nwIPv6Subnets []networktypes.NetworkSubnet
  531. for _, nwIPAMConfig := range v4Configs {
  532. nwIPv4Subnets = append(nwIPv4Subnets, nwIPAMConfig)
  533. }
  534. for _, nwIPAMConfig := range v6Configs {
  535. nwIPv6Subnets = append(nwIPv6Subnets, nwIPAMConfig)
  536. }
  537. // TODO(aker): add a proper multierror.Append
  538. if err := ipamConfig.IsInRange(nwIPv4Subnets, nwIPv6Subnets); err != nil {
  539. errs = append(errs, err.(interface{ Unwrap() []error }).Unwrap()...)
  540. }
  541. }
  542. if epConfig.MacAddress != "" {
  543. _, err := net.ParseMAC(epConfig.MacAddress)
  544. if err != nil {
  545. return fmt.Errorf("invalid MAC address %s", epConfig.MacAddress)
  546. }
  547. }
  548. if err := multierror.Join(errs...); err != nil {
  549. return fmt.Errorf("invalid endpoint settings:\n%w", err)
  550. }
  551. return nil
  552. }
  553. // cleanOperationalData resets the operational data from the passed endpoint settings
  554. func cleanOperationalData(es *network.EndpointSettings) {
  555. es.EndpointID = ""
  556. es.Gateway = ""
  557. es.IPAddress = ""
  558. es.IPPrefixLen = 0
  559. es.IPv6Gateway = ""
  560. es.GlobalIPv6Address = ""
  561. es.GlobalIPv6PrefixLen = 0
  562. if es.IPAMOperational {
  563. es.IPAMConfig = nil
  564. }
  565. }
  566. func (daemon *Daemon) updateNetworkConfig(container *container.Container, n *libnetwork.Network, endpointConfig *networktypes.EndpointSettings, updateSettings bool) error {
  567. if containertypes.NetworkMode(n.Name()).IsUserDefined() {
  568. addShortID := true
  569. shortID := stringid.TruncateID(container.ID)
  570. for _, alias := range endpointConfig.Aliases {
  571. if alias == shortID {
  572. addShortID = false
  573. break
  574. }
  575. }
  576. if addShortID {
  577. endpointConfig.Aliases = append(endpointConfig.Aliases, shortID)
  578. }
  579. if container.Name != container.Config.Hostname {
  580. addHostname := true
  581. for _, alias := range endpointConfig.Aliases {
  582. if alias == container.Config.Hostname {
  583. addHostname = false
  584. break
  585. }
  586. }
  587. if addHostname {
  588. endpointConfig.Aliases = append(endpointConfig.Aliases, container.Config.Hostname)
  589. }
  590. }
  591. }
  592. if err := validateEndpointSettings(n, n.Name(), endpointConfig); err != nil {
  593. return err
  594. }
  595. if updateSettings {
  596. if err := daemon.updateNetworkSettings(container, n, endpointConfig); err != nil {
  597. return err
  598. }
  599. }
  600. return nil
  601. }
  602. func (daemon *Daemon) connectToNetwork(cfg *config.Config, container *container.Container, idOrName string, endpointConfig *networktypes.EndpointSettings, updateSettings bool) (err error) {
  603. start := time.Now()
  604. if container.HostConfig.NetworkMode.IsContainer() {
  605. return runconfig.ErrConflictSharedNetwork
  606. }
  607. if cfg.DisableBridge && containertypes.NetworkMode(idOrName).IsBridge() {
  608. container.Config.NetworkDisabled = true
  609. return nil
  610. }
  611. if endpointConfig == nil {
  612. endpointConfig = &networktypes.EndpointSettings{}
  613. }
  614. n, nwCfg, err := daemon.findAndAttachNetwork(container, idOrName, endpointConfig)
  615. if err != nil {
  616. return err
  617. }
  618. if n == nil {
  619. return nil
  620. }
  621. nwName := n.Name()
  622. if idOrName != container.HostConfig.NetworkMode.NetworkName() {
  623. if err := daemon.normalizeNetMode(container); err != nil {
  624. return err
  625. }
  626. }
  627. var operIPAM bool
  628. if nwCfg != nil {
  629. if epConfig, ok := nwCfg.EndpointsConfig[nwName]; ok {
  630. if endpointConfig.IPAMConfig == nil || (endpointConfig.IPAMConfig.IPv4Address == "" && endpointConfig.IPAMConfig.IPv6Address == "" && len(endpointConfig.IPAMConfig.LinkLocalIPs) == 0) {
  631. operIPAM = true
  632. }
  633. // copy IPAMConfig and NetworkID from epConfig via AttachNetwork
  634. endpointConfig.IPAMConfig = epConfig.IPAMConfig
  635. endpointConfig.NetworkID = epConfig.NetworkID
  636. }
  637. }
  638. if err := daemon.updateNetworkConfig(container, n, endpointConfig, updateSettings); err != nil {
  639. return err
  640. }
  641. // TODO(thaJeztah): should this fail early if no sandbox was found?
  642. sb, _ := daemon.netController.GetSandbox(container.ID)
  643. createOptions, err := buildCreateEndpointOptions(container, n, endpointConfig, sb, ipAddresses(cfg.DNS))
  644. if err != nil {
  645. return err
  646. }
  647. endpointName := strings.TrimPrefix(container.Name, "/")
  648. ep, err := n.CreateEndpoint(endpointName, createOptions...)
  649. if err != nil {
  650. return err
  651. }
  652. defer func() {
  653. if err != nil {
  654. if e := ep.Delete(false); e != nil {
  655. log.G(context.TODO()).Warnf("Could not rollback container connection to network %s", idOrName)
  656. }
  657. }
  658. }()
  659. container.NetworkSettings.Networks[nwName] = &network.EndpointSettings{
  660. EndpointSettings: endpointConfig,
  661. IPAMOperational: operIPAM,
  662. }
  663. delete(container.NetworkSettings.Networks, n.ID())
  664. if err := daemon.updateEndpointNetworkSettings(cfg, container, n, ep); err != nil {
  665. return err
  666. }
  667. if sb == nil {
  668. sbOptions, err := daemon.buildSandboxOptions(cfg, container)
  669. if err != nil {
  670. return err
  671. }
  672. sb, err = daemon.netController.NewSandbox(container.ID, sbOptions...)
  673. if err != nil {
  674. return err
  675. }
  676. setNetworkSandbox(container, sb)
  677. }
  678. joinOptions, err := buildJoinOptions(container.NetworkSettings, n)
  679. if err != nil {
  680. return err
  681. }
  682. if err := ep.Join(sb, joinOptions...); err != nil {
  683. return err
  684. }
  685. if !container.Managed {
  686. // add container name/alias to DNS
  687. if err := daemon.ActivateContainerServiceBinding(container.Name); err != nil {
  688. return fmt.Errorf("Activate container service binding for %s failed: %v", container.Name, err)
  689. }
  690. }
  691. if err := updateJoinInfo(container.NetworkSettings, n, ep); err != nil {
  692. return fmt.Errorf("Updating join info failed: %v", err)
  693. }
  694. container.NetworkSettings.Ports = getPortMapInfo(sb)
  695. daemon.LogNetworkEventWithAttributes(n, events.ActionConnect, map[string]string{"container": container.ID})
  696. networkActions.WithValues("connect").UpdateSince(start)
  697. return nil
  698. }
  699. func updateJoinInfo(networkSettings *network.Settings, n *libnetwork.Network, ep *libnetwork.Endpoint) error {
  700. if ep == nil {
  701. return errors.New("invalid enppoint whhile building portmap info")
  702. }
  703. if networkSettings == nil {
  704. return errors.New("invalid network settings while building port map info")
  705. }
  706. if len(networkSettings.Ports) == 0 {
  707. pm, err := getEndpointPortMapInfo(ep)
  708. if err != nil {
  709. return err
  710. }
  711. networkSettings.Ports = pm
  712. }
  713. epInfo := ep.Info()
  714. if epInfo == nil {
  715. // It is not an error to get an empty endpoint info
  716. return nil
  717. }
  718. if epInfo.Gateway() != nil {
  719. networkSettings.Networks[n.Name()].Gateway = epInfo.Gateway().String()
  720. }
  721. if epInfo.GatewayIPv6().To16() != nil {
  722. networkSettings.Networks[n.Name()].IPv6Gateway = epInfo.GatewayIPv6().String()
  723. }
  724. return nil
  725. }
  726. // ForceEndpointDelete deletes an endpoint from a network forcefully
  727. func (daemon *Daemon) ForceEndpointDelete(name string, networkName string) error {
  728. n, err := daemon.FindNetwork(networkName)
  729. if err != nil {
  730. return err
  731. }
  732. ep, err := n.EndpointByName(name)
  733. if err != nil {
  734. return err
  735. }
  736. return ep.Delete(true)
  737. }
  738. func (daemon *Daemon) disconnectFromNetwork(container *container.Container, n *libnetwork.Network, force bool) error {
  739. var (
  740. ep *libnetwork.Endpoint
  741. sbox *libnetwork.Sandbox
  742. )
  743. n.WalkEndpoints(func(current *libnetwork.Endpoint) bool {
  744. epInfo := current.Info()
  745. if epInfo == nil {
  746. return false
  747. }
  748. if sb := epInfo.Sandbox(); sb != nil {
  749. if sb.ContainerID() == container.ID {
  750. ep = current
  751. sbox = sb
  752. return true
  753. }
  754. }
  755. return false
  756. })
  757. if ep == nil {
  758. if force {
  759. var err error
  760. ep, err = n.EndpointByName(strings.TrimPrefix(container.Name, "/"))
  761. if err != nil {
  762. return err
  763. }
  764. return ep.Delete(force)
  765. }
  766. return fmt.Errorf("container %s is not connected to network %s", container.ID, n.Name())
  767. }
  768. if err := ep.Leave(sbox); err != nil {
  769. return fmt.Errorf("container %s failed to leave network %s: %v", container.ID, n.Name(), err)
  770. }
  771. container.NetworkSettings.Ports = getPortMapInfo(sbox)
  772. if err := ep.Delete(false); err != nil {
  773. return fmt.Errorf("endpoint delete failed for container %s on network %s: %v", container.ID, n.Name(), err)
  774. }
  775. delete(container.NetworkSettings.Networks, n.Name())
  776. daemon.tryDetachContainerFromClusterNetwork(n, container)
  777. return nil
  778. }
  779. func (daemon *Daemon) tryDetachContainerFromClusterNetwork(network *libnetwork.Network, container *container.Container) {
  780. if !container.Managed && daemon.clusterProvider != nil && network.Dynamic() {
  781. if err := daemon.clusterProvider.DetachNetwork(network.Name(), container.ID); err != nil {
  782. log.G(context.TODO()).WithError(err).Warn("error detaching from network")
  783. if err := daemon.clusterProvider.DetachNetwork(network.ID(), container.ID); err != nil {
  784. log.G(context.TODO()).WithError(err).Warn("error detaching from network")
  785. }
  786. }
  787. }
  788. daemon.LogNetworkEventWithAttributes(network, events.ActionDisconnect, map[string]string{
  789. "container": container.ID,
  790. })
  791. }
  792. // normalizeNetMode checks whether the network mode references a network by a partial ID. In that case, it replaces the
  793. // partial ID with the full network ID.
  794. // TODO(aker): transform ID into name when the referenced network is one of the predefined.
  795. func (daemon *Daemon) normalizeNetMode(container *container.Container) error {
  796. if container.HostConfig.NetworkMode.IsUserDefined() {
  797. netMode := container.HostConfig.NetworkMode.NetworkName()
  798. nw, err := daemon.FindNetwork(netMode)
  799. if err != nil {
  800. return fmt.Errorf("could not find a network matching network mode %s: %w", netMode, err)
  801. }
  802. if netMode != nw.ID() && netMode != nw.Name() {
  803. container.HostConfig.NetworkMode = containertypes.NetworkMode(nw.ID())
  804. }
  805. }
  806. return nil
  807. }
  808. func (daemon *Daemon) initializeNetworking(cfg *config.Config, container *container.Container) error {
  809. if container.HostConfig.NetworkMode.IsContainer() {
  810. // we need to get the hosts files from the container to join
  811. nc, err := daemon.getNetworkedContainer(container.ID, container.HostConfig.NetworkMode.ConnectedContainer())
  812. if err != nil {
  813. return err
  814. }
  815. err = daemon.initializeNetworkingPaths(container, nc)
  816. if err != nil {
  817. return err
  818. }
  819. container.Config.Hostname = nc.Config.Hostname
  820. container.Config.Domainname = nc.Config.Domainname
  821. return nil
  822. }
  823. if container.HostConfig.NetworkMode.IsHost() && container.Config.Hostname == "" {
  824. hn, err := os.Hostname()
  825. if err != nil {
  826. return err
  827. }
  828. container.Config.Hostname = hn
  829. }
  830. if err := daemon.allocateNetwork(cfg, container); err != nil {
  831. return err
  832. }
  833. return container.BuildHostnameFile()
  834. }
  835. func (daemon *Daemon) getNetworkedContainer(containerID, connectedContainerID string) (*container.Container, error) {
  836. nc, err := daemon.GetContainer(connectedContainerID)
  837. if err != nil {
  838. return nil, err
  839. }
  840. if containerID == nc.ID {
  841. return nil, fmt.Errorf("cannot join own network")
  842. }
  843. if !nc.IsRunning() {
  844. return nil, errdefs.Conflict(fmt.Errorf("cannot join network of a non running container: %s", connectedContainerID))
  845. }
  846. if nc.IsRestarting() {
  847. return nil, errContainerIsRestarting(connectedContainerID)
  848. }
  849. return nc, nil
  850. }
  851. func (daemon *Daemon) releaseNetwork(container *container.Container) {
  852. start := time.Now()
  853. // If live-restore is enabled, the daemon cleans up dead containers when it starts up. In that case, the
  854. // netController hasn't been initialized yet and so we can't proceed.
  855. // TODO(aker): If we hit this case, the endpoint state won't be cleaned up (ie. no call to cleanOperationalData).
  856. if daemon.netController == nil {
  857. return
  858. }
  859. // If the container uses the network namespace of another container, it doesn't own it -- nothing to do here.
  860. if container.HostConfig.NetworkMode.IsContainer() {
  861. return
  862. }
  863. if container.NetworkSettings == nil {
  864. return
  865. }
  866. container.NetworkSettings.Ports = nil
  867. sid := container.NetworkSettings.SandboxID
  868. if sid == "" {
  869. return
  870. }
  871. var networks []*libnetwork.Network
  872. for n, epSettings := range container.NetworkSettings.Networks {
  873. if nw, err := daemon.FindNetwork(getNetworkID(n, epSettings.EndpointSettings)); err == nil {
  874. networks = append(networks, nw)
  875. }
  876. if epSettings.EndpointSettings == nil {
  877. continue
  878. }
  879. cleanOperationalData(epSettings)
  880. }
  881. sb, err := daemon.netController.SandboxByID(sid)
  882. if err != nil {
  883. log.G(context.TODO()).Warnf("error locating sandbox id %s: %v", sid, err)
  884. return
  885. }
  886. if err := sb.Delete(); err != nil {
  887. log.G(context.TODO()).Errorf("Error deleting sandbox id %s for container %s: %v", sid, container.ID, err)
  888. }
  889. for _, nw := range networks {
  890. daemon.tryDetachContainerFromClusterNetwork(nw, container)
  891. }
  892. networkActions.WithValues("release").UpdateSince(start)
  893. }
  894. func errRemovalContainer(containerID string) error {
  895. return fmt.Errorf("Container %s is marked for removal and cannot be connected or disconnected to the network", containerID)
  896. }
  897. // ConnectToNetwork connects a container to a network
  898. func (daemon *Daemon) ConnectToNetwork(container *container.Container, idOrName string, endpointConfig *networktypes.EndpointSettings) error {
  899. if endpointConfig == nil {
  900. endpointConfig = &networktypes.EndpointSettings{}
  901. }
  902. container.Lock()
  903. defer container.Unlock()
  904. if !container.Running {
  905. if container.RemovalInProgress || container.Dead {
  906. return errRemovalContainer(container.ID)
  907. }
  908. n, err := daemon.FindNetwork(idOrName)
  909. if err == nil && n != nil {
  910. if err := daemon.updateNetworkConfig(container, n, endpointConfig, true); err != nil {
  911. return err
  912. }
  913. } else {
  914. container.NetworkSettings.Networks[idOrName] = &network.EndpointSettings{
  915. EndpointSettings: endpointConfig,
  916. }
  917. }
  918. } else {
  919. if err := daemon.connectToNetwork(&daemon.config().Config, container, idOrName, endpointConfig, true); err != nil {
  920. return err
  921. }
  922. }
  923. return container.CheckpointTo(daemon.containersReplica)
  924. }
  925. // DisconnectFromNetwork disconnects container from network n.
  926. func (daemon *Daemon) DisconnectFromNetwork(container *container.Container, networkName string, force bool) error {
  927. n, err := daemon.FindNetwork(networkName)
  928. container.Lock()
  929. defer container.Unlock()
  930. if !container.Running || (err != nil && force) {
  931. if container.RemovalInProgress || container.Dead {
  932. return errRemovalContainer(container.ID)
  933. }
  934. // In case networkName is resolved we will use n.Name()
  935. // this will cover the case where network id is passed.
  936. if n != nil {
  937. networkName = n.Name()
  938. }
  939. if _, ok := container.NetworkSettings.Networks[networkName]; !ok {
  940. return fmt.Errorf("container %s is not connected to the network %s", container.ID, networkName)
  941. }
  942. delete(container.NetworkSettings.Networks, networkName)
  943. } else if err == nil {
  944. if container.HostConfig.NetworkMode.IsHost() && containertypes.NetworkMode(n.Type()).IsHost() {
  945. return runconfig.ErrConflictHostNetwork
  946. }
  947. if err := daemon.disconnectFromNetwork(container, n, false); err != nil {
  948. return err
  949. }
  950. } else {
  951. return err
  952. }
  953. if err := container.CheckpointTo(daemon.containersReplica); err != nil {
  954. return err
  955. }
  956. if n != nil {
  957. daemon.LogNetworkEventWithAttributes(n, events.ActionDisconnect, map[string]string{
  958. "container": container.ID,
  959. })
  960. }
  961. return nil
  962. }
  963. // ActivateContainerServiceBinding puts this container into load balancer active rotation and DNS response
  964. func (daemon *Daemon) ActivateContainerServiceBinding(containerName string) error {
  965. ctr, err := daemon.GetContainer(containerName)
  966. if err != nil {
  967. return err
  968. }
  969. sb, err := daemon.netController.GetSandbox(ctr.ID)
  970. if err != nil {
  971. return fmt.Errorf("failed to activate service binding for container %s: %w", containerName, err)
  972. }
  973. return sb.EnableService()
  974. }
  975. // DeactivateContainerServiceBinding removes this container from load balancer active rotation, and DNS response
  976. func (daemon *Daemon) DeactivateContainerServiceBinding(containerName string) error {
  977. ctr, err := daemon.GetContainer(containerName)
  978. if err != nil {
  979. return err
  980. }
  981. sb, err := daemon.netController.GetSandbox(ctr.ID)
  982. if err != nil {
  983. // If the network sandbox is not found, then there is nothing to deactivate
  984. log.G(context.TODO()).WithError(err).Debugf("Could not find network sandbox for container %s on service binding deactivation request", containerName)
  985. return nil
  986. }
  987. return sb.DisableService()
  988. }
  989. func getNetworkID(name string, endpointSettings *networktypes.EndpointSettings) string {
  990. // We only want to prefer NetworkID for user defined networks.
  991. // For systems like bridge, none, etc. the name is preferred (otherwise restart may cause issues)
  992. if containertypes.NetworkMode(name).IsUserDefined() && endpointSettings != nil && endpointSettings.NetworkID != "" {
  993. return endpointSettings.NetworkID
  994. }
  995. return name
  996. }
  997. // setNetworkSandbox updates the sandbox ID and Key.
  998. func setNetworkSandbox(c *container.Container, sb *libnetwork.Sandbox) {
  999. c.NetworkSettings.SandboxID = sb.ID()
  1000. c.NetworkSettings.SandboxKey = sb.Key()
  1001. }