endpoint.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994
  1. package libnetwork
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "io/ioutil"
  7. "os"
  8. "path"
  9. "path/filepath"
  10. "sync"
  11. log "github.com/Sirupsen/logrus"
  12. "github.com/docker/docker/pkg/ioutils"
  13. "github.com/docker/libnetwork/datastore"
  14. "github.com/docker/libnetwork/etchosts"
  15. "github.com/docker/libnetwork/netlabel"
  16. "github.com/docker/libnetwork/resolvconf"
  17. "github.com/docker/libnetwork/sandbox"
  18. "github.com/docker/libnetwork/types"
  19. )
  20. // Endpoint represents a logical connection between a network and a sandbox.
  21. type Endpoint interface {
  22. // A system generated id for this endpoint.
  23. ID() string
  24. // Name returns the name of this endpoint.
  25. Name() string
  26. // Network returns the name of the network to which this endpoint is attached.
  27. Network() string
  28. // Join creates a new sandbox for the given container ID and populates the
  29. // network resources allocated for the endpoint and joins the sandbox to
  30. // the endpoint.
  31. Join(containerID string, options ...EndpointOption) error
  32. // Leave removes the sandbox associated with container ID and detaches
  33. // the network resources populated in the sandbox
  34. Leave(containerID string, options ...EndpointOption) error
  35. // Return certain operational data belonging to this endpoint
  36. Info() EndpointInfo
  37. // DriverInfo returns a collection of driver operational data related to this endpoint retrieved from the driver
  38. DriverInfo() (map[string]interface{}, error)
  39. // ContainerInfo returns the info available at the endpoint about the attached container
  40. ContainerInfo() ContainerInfo
  41. // Delete and detaches this endpoint from the network.
  42. Delete() error
  43. // Retrieve the interfaces' statistics from the sandbox
  44. Statistics() (map[string]*sandbox.InterfaceStatistics, error)
  45. }
  46. // EndpointOption is a option setter function type used to pass varios options to Network
  47. // and Endpoint interfaces methods. The various setter functions of type EndpointOption are
  48. // provided by libnetwork, they look like <Create|Join|Leave>Option[...](...)
  49. type EndpointOption func(ep *endpoint)
  50. // ContainerData is a set of data returned when a container joins an endpoint.
  51. type ContainerData struct {
  52. SandboxKey string
  53. }
  54. // These are the container configs used to customize container /etc/hosts file.
  55. type hostsPathConfig struct {
  56. hostName string
  57. domainName string
  58. hostsPath string
  59. extraHosts []extraHost
  60. parentUpdates []parentUpdate
  61. }
  62. // These are the container configs used to customize container /etc/resolv.conf file.
  63. type resolvConfPathConfig struct {
  64. resolvConfPath string
  65. dnsList []string
  66. dnsSearchList []string
  67. }
  68. type containerConfig struct {
  69. hostsPathConfig
  70. resolvConfPathConfig
  71. generic map[string]interface{}
  72. useDefaultSandBox bool
  73. prio int // higher the value, more the priority
  74. }
  75. type extraHost struct {
  76. name string
  77. IP string
  78. }
  79. type parentUpdate struct {
  80. eid string
  81. name string
  82. ip string
  83. }
  84. type containerInfo struct {
  85. id string
  86. config containerConfig
  87. data ContainerData
  88. sync.Mutex
  89. }
  90. func (ci *containerInfo) ID() string {
  91. return ci.id
  92. }
  93. func (ci *containerInfo) Labels() map[string]interface{} {
  94. return ci.config.generic
  95. }
  96. type endpoint struct {
  97. name string
  98. id types.UUID
  99. network *network
  100. iFaces []*endpointInterface
  101. joinInfo *endpointJoinInfo
  102. container *containerInfo
  103. exposedPorts []types.TransportPort
  104. generic map[string]interface{}
  105. joinLeaveDone chan struct{}
  106. dbIndex uint64
  107. dbExists bool
  108. sync.Mutex
  109. }
  110. func (ci *containerInfo) MarshalJSON() ([]byte, error) {
  111. ci.Lock()
  112. defer ci.Unlock()
  113. // We are just interested in the container ID. This can be expanded to include all of containerInfo if there is a need
  114. return json.Marshal(ci.id)
  115. }
  116. func (ci *containerInfo) UnmarshalJSON(b []byte) (err error) {
  117. ci.Lock()
  118. defer ci.Unlock()
  119. var id string
  120. if err := json.Unmarshal(b, &id); err != nil {
  121. return err
  122. }
  123. ci.id = id
  124. return nil
  125. }
  126. func (ep *endpoint) MarshalJSON() ([]byte, error) {
  127. ep.Lock()
  128. defer ep.Unlock()
  129. epMap := make(map[string]interface{})
  130. epMap["name"] = ep.name
  131. epMap["id"] = string(ep.id)
  132. epMap["ep_iface"] = ep.iFaces
  133. epMap["exposed_ports"] = ep.exposedPorts
  134. epMap["generic"] = ep.generic
  135. if ep.container != nil {
  136. epMap["container"] = ep.container
  137. }
  138. return json.Marshal(epMap)
  139. }
  140. func (ep *endpoint) UnmarshalJSON(b []byte) (err error) {
  141. ep.Lock()
  142. defer ep.Unlock()
  143. var epMap map[string]interface{}
  144. if err := json.Unmarshal(b, &epMap); err != nil {
  145. return err
  146. }
  147. ep.name = epMap["name"].(string)
  148. ep.id = types.UUID(epMap["id"].(string))
  149. ib, _ := json.Marshal(epMap["ep_iface"])
  150. var ifaces []endpointInterface
  151. json.Unmarshal(ib, &ifaces)
  152. ep.iFaces = make([]*endpointInterface, 0)
  153. for _, iface := range ifaces {
  154. ep.iFaces = append(ep.iFaces, &iface)
  155. }
  156. tb, _ := json.Marshal(epMap["exposed_ports"])
  157. var tPorts []types.TransportPort
  158. json.Unmarshal(tb, &tPorts)
  159. ep.exposedPorts = tPorts
  160. epc, ok := epMap["container"]
  161. if ok {
  162. cb, _ := json.Marshal(epc)
  163. var cInfo containerInfo
  164. json.Unmarshal(cb, &cInfo)
  165. ep.container = &cInfo
  166. }
  167. if epMap["generic"] != nil {
  168. ep.generic = epMap["generic"].(map[string]interface{})
  169. }
  170. return nil
  171. }
  172. const defaultPrefix = "/var/lib/docker/network/files"
  173. func (ep *endpoint) ID() string {
  174. ep.Lock()
  175. defer ep.Unlock()
  176. return string(ep.id)
  177. }
  178. func (ep *endpoint) Name() string {
  179. ep.Lock()
  180. defer ep.Unlock()
  181. return ep.name
  182. }
  183. func (ep *endpoint) Network() string {
  184. ep.Lock()
  185. defer ep.Unlock()
  186. return ep.network.name
  187. }
  188. // endpoint Key structure : endpoint/network-id/endpoint-id
  189. func (ep *endpoint) Key() []string {
  190. ep.Lock()
  191. n := ep.network
  192. defer ep.Unlock()
  193. return []string{datastore.EndpointKeyPrefix, string(n.id), string(ep.id)}
  194. }
  195. func (ep *endpoint) KeyPrefix() []string {
  196. ep.Lock()
  197. n := ep.network
  198. defer ep.Unlock()
  199. return []string{datastore.EndpointKeyPrefix, string(n.id)}
  200. }
  201. func (ep *endpoint) networkIDFromKey(key []string) (types.UUID, error) {
  202. // endpoint Key structure : endpoint/network-id/endpoint-id
  203. // it's an invalid key if the key doesn't have all the 3 key elements above
  204. if key == nil || len(key) < 3 || key[0] != datastore.EndpointKeyPrefix {
  205. return types.UUID(""), fmt.Errorf("invalid endpoint key : %v", key)
  206. }
  207. // network-id is placed at index=1. pls refer to endpoint.Key() method
  208. return types.UUID(key[1]), nil
  209. }
  210. func (ep *endpoint) Value() []byte {
  211. b, err := json.Marshal(ep)
  212. if err != nil {
  213. return nil
  214. }
  215. return b
  216. }
  217. func (ep *endpoint) SetValue(value []byte) error {
  218. return json.Unmarshal(value, ep)
  219. }
  220. func (ep *endpoint) Index() uint64 {
  221. ep.Lock()
  222. defer ep.Unlock()
  223. return ep.dbIndex
  224. }
  225. func (ep *endpoint) SetIndex(index uint64) {
  226. ep.Lock()
  227. defer ep.Unlock()
  228. ep.dbIndex = index
  229. ep.dbExists = true
  230. }
  231. func (ep *endpoint) Exists() bool {
  232. ep.Lock()
  233. defer ep.Unlock()
  234. return ep.dbExists
  235. }
  236. func (ep *endpoint) processOptions(options ...EndpointOption) {
  237. ep.Lock()
  238. defer ep.Unlock()
  239. for _, opt := range options {
  240. if opt != nil {
  241. opt(ep)
  242. }
  243. }
  244. }
  245. func createBasePath(dir string) error {
  246. return os.MkdirAll(dir, 0644)
  247. }
  248. func createFile(path string) error {
  249. var f *os.File
  250. dir, _ := filepath.Split(path)
  251. err := createBasePath(dir)
  252. if err != nil {
  253. return err
  254. }
  255. f, err = os.Create(path)
  256. if err == nil {
  257. f.Close()
  258. }
  259. return err
  260. }
  261. // joinLeaveStart waits to ensure there are no joins or leaves in progress and
  262. // marks this join/leave in progress without race
  263. func (ep *endpoint) joinLeaveStart() {
  264. ep.Lock()
  265. defer ep.Unlock()
  266. for ep.joinLeaveDone != nil {
  267. joinLeaveDone := ep.joinLeaveDone
  268. ep.Unlock()
  269. select {
  270. case <-joinLeaveDone:
  271. }
  272. ep.Lock()
  273. }
  274. ep.joinLeaveDone = make(chan struct{})
  275. }
  276. // joinLeaveEnd marks the end of this join/leave operation and
  277. // signals the same without race to other join and leave waiters
  278. func (ep *endpoint) joinLeaveEnd() {
  279. ep.Lock()
  280. defer ep.Unlock()
  281. if ep.joinLeaveDone != nil {
  282. close(ep.joinLeaveDone)
  283. ep.joinLeaveDone = nil
  284. }
  285. }
  286. func (ep *endpoint) Join(containerID string, options ...EndpointOption) error {
  287. var err error
  288. if containerID == "" {
  289. return InvalidContainerIDError(containerID)
  290. }
  291. ep.joinLeaveStart()
  292. defer func() {
  293. ep.joinLeaveEnd()
  294. }()
  295. ep.Lock()
  296. if ep.container != nil {
  297. ep.Unlock()
  298. return ErrInvalidJoin{}
  299. }
  300. ep.container = &containerInfo{
  301. id: containerID,
  302. config: containerConfig{
  303. hostsPathConfig: hostsPathConfig{
  304. extraHosts: []extraHost{},
  305. parentUpdates: []parentUpdate{},
  306. },
  307. }}
  308. ep.joinInfo = &endpointJoinInfo{}
  309. container := ep.container
  310. network := ep.network
  311. epid := ep.id
  312. ep.Unlock()
  313. defer func() {
  314. if err != nil {
  315. ep.Lock()
  316. ep.container = nil
  317. ep.Unlock()
  318. }
  319. }()
  320. network.Lock()
  321. driver := network.driver
  322. nid := network.id
  323. ctrlr := network.ctrlr
  324. network.Unlock()
  325. ep.processOptions(options...)
  326. sboxKey := sandbox.GenerateKey(containerID)
  327. if container.config.useDefaultSandBox {
  328. sboxKey = sandbox.GenerateKey("default")
  329. }
  330. err = driver.Join(nid, epid, sboxKey, ep, container.config.generic)
  331. if err != nil {
  332. return err
  333. }
  334. defer func() {
  335. if err != nil {
  336. // Do not alter global err variable, it's needed by the previous defer
  337. if err := driver.Leave(nid, epid); err != nil {
  338. log.Warnf("driver leave failed while rolling back join: %v", err)
  339. }
  340. }
  341. }()
  342. err = ep.buildHostsFiles()
  343. if err != nil {
  344. return err
  345. }
  346. err = ep.updateParentHosts()
  347. if err != nil {
  348. return err
  349. }
  350. err = ep.setupDNS()
  351. if err != nil {
  352. return err
  353. }
  354. sb, err := ctrlr.sandboxAdd(sboxKey, !container.config.useDefaultSandBox, ep)
  355. if err != nil {
  356. return fmt.Errorf("failed sandbox add: %v", err)
  357. }
  358. defer func() {
  359. if err != nil {
  360. ctrlr.sandboxRm(sboxKey, ep)
  361. }
  362. }()
  363. if err := network.ctrlr.updateEndpointToStore(ep); err != nil {
  364. return err
  365. }
  366. container.data.SandboxKey = sb.Key()
  367. return nil
  368. }
  369. func (ep *endpoint) hasInterface(iName string) bool {
  370. ep.Lock()
  371. defer ep.Unlock()
  372. for _, iface := range ep.iFaces {
  373. if iface.srcName == iName {
  374. return true
  375. }
  376. }
  377. return false
  378. }
  379. func (ep *endpoint) Leave(containerID string, options ...EndpointOption) error {
  380. var err error
  381. ep.joinLeaveStart()
  382. defer ep.joinLeaveEnd()
  383. ep.processOptions(options...)
  384. ep.Lock()
  385. container := ep.container
  386. n := ep.network
  387. if container == nil || container.id == "" || container.data.SandboxKey == "" ||
  388. containerID == "" || container.id != containerID {
  389. if container == nil {
  390. err = ErrNoContainer{}
  391. } else {
  392. err = InvalidContainerIDError(containerID)
  393. }
  394. ep.Unlock()
  395. return err
  396. }
  397. ep.container = nil
  398. ep.Unlock()
  399. n.Lock()
  400. driver := n.driver
  401. ctrlr := n.ctrlr
  402. n.Unlock()
  403. if err := ctrlr.updateEndpointToStore(ep); err != nil {
  404. ep.Lock()
  405. ep.container = container
  406. ep.Unlock()
  407. return err
  408. }
  409. err = driver.Leave(n.id, ep.id)
  410. ctrlr.sandboxRm(container.data.SandboxKey, ep)
  411. return err
  412. }
  413. func (ep *endpoint) Delete() error {
  414. var err error
  415. ep.Lock()
  416. epid := ep.id
  417. name := ep.name
  418. n := ep.network
  419. if ep.container != nil {
  420. ep.Unlock()
  421. return &ActiveContainerError{name: name, id: string(epid)}
  422. }
  423. n.Lock()
  424. ctrlr := n.ctrlr
  425. n.Unlock()
  426. ep.Unlock()
  427. if err = ctrlr.deleteEndpointFromStore(ep); err != nil {
  428. return err
  429. }
  430. defer func() {
  431. if err != nil {
  432. ep.SetIndex(0)
  433. if e := ctrlr.updateEndpointToStore(ep); e != nil {
  434. log.Warnf("failed to recreate endpoint in store %s : %v", name, err)
  435. }
  436. }
  437. }()
  438. // Update the endpoint count in network and update it in the datastore
  439. n.DecEndpointCnt()
  440. if err = ctrlr.updateNetworkToStore(n); err != nil {
  441. return err
  442. }
  443. defer func() {
  444. if err != nil {
  445. n.IncEndpointCnt()
  446. if e := ctrlr.updateNetworkToStore(n); e != nil {
  447. log.Warnf("failed to update network %s : %v", n.name, e)
  448. }
  449. }
  450. }()
  451. if err = ep.deleteEndpoint(); err != nil {
  452. return err
  453. }
  454. return nil
  455. }
  456. func (ep *endpoint) Statistics() (map[string]*sandbox.InterfaceStatistics, error) {
  457. m := make(map[string]*sandbox.InterfaceStatistics)
  458. ep.Lock()
  459. n := ep.network
  460. skey := ep.container.data.SandboxKey
  461. ep.Unlock()
  462. n.Lock()
  463. c := n.ctrlr
  464. n.Unlock()
  465. sbox := c.sandboxGet(skey)
  466. if sbox == nil {
  467. return m, nil
  468. }
  469. var err error
  470. for _, i := range sbox.Info().Interfaces() {
  471. if m[i.DstName()], err = i.Statistics(); err != nil {
  472. return m, err
  473. }
  474. }
  475. return m, nil
  476. }
  477. func (ep *endpoint) deleteEndpoint() error {
  478. ep.Lock()
  479. n := ep.network
  480. name := ep.name
  481. epid := ep.id
  482. ep.Unlock()
  483. n.Lock()
  484. _, ok := n.endpoints[epid]
  485. if !ok {
  486. n.Unlock()
  487. return nil
  488. }
  489. nid := n.id
  490. driver := n.driver
  491. delete(n.endpoints, epid)
  492. n.Unlock()
  493. if err := driver.DeleteEndpoint(nid, epid); err != nil {
  494. if _, ok := err.(types.ForbiddenError); ok {
  495. n.Lock()
  496. n.endpoints[epid] = ep
  497. n.Unlock()
  498. return err
  499. }
  500. log.Warnf("driver error deleting endpoint %s : %v", name, err)
  501. }
  502. n.updateSvcRecord(ep, false)
  503. return nil
  504. }
  505. func (ep *endpoint) addHostEntries(recs []etchosts.Record) {
  506. ep.Lock()
  507. container := ep.container
  508. ep.Unlock()
  509. if container == nil {
  510. return
  511. }
  512. if err := etchosts.Add(container.config.hostsPath, recs); err != nil {
  513. log.Warnf("Failed adding service host entries to the running container: %v", err)
  514. }
  515. }
  516. func (ep *endpoint) deleteHostEntries(recs []etchosts.Record) {
  517. ep.Lock()
  518. container := ep.container
  519. ep.Unlock()
  520. if container == nil {
  521. return
  522. }
  523. if err := etchosts.Delete(container.config.hostsPath, recs); err != nil {
  524. log.Warnf("Failed deleting service host entries to the running container: %v", err)
  525. }
  526. }
  527. func (ep *endpoint) buildHostsFiles() error {
  528. var extraContent []etchosts.Record
  529. ep.Lock()
  530. container := ep.container
  531. joinInfo := ep.joinInfo
  532. ifaces := ep.iFaces
  533. n := ep.network
  534. ep.Unlock()
  535. if container == nil {
  536. return ErrNoContainer{}
  537. }
  538. if container.config.hostsPath == "" {
  539. container.config.hostsPath = defaultPrefix + "/" + container.id + "/hosts"
  540. }
  541. dir, _ := filepath.Split(container.config.hostsPath)
  542. err := createBasePath(dir)
  543. if err != nil {
  544. return err
  545. }
  546. if joinInfo != nil && joinInfo.hostsPath != "" {
  547. content, err := ioutil.ReadFile(joinInfo.hostsPath)
  548. if err != nil && !os.IsNotExist(err) {
  549. return err
  550. }
  551. if err == nil {
  552. return ioutil.WriteFile(container.config.hostsPath, content, 0644)
  553. }
  554. }
  555. for _, extraHost := range container.config.extraHosts {
  556. extraContent = append(extraContent,
  557. etchosts.Record{Hosts: extraHost.name, IP: extraHost.IP})
  558. }
  559. extraContent = append(extraContent, n.getSvcRecords()...)
  560. IP := ""
  561. if len(ifaces) != 0 && ifaces[0] != nil {
  562. IP = ifaces[0].addr.IP.String()
  563. }
  564. return etchosts.Build(container.config.hostsPath, IP, container.config.hostName,
  565. container.config.domainName, extraContent)
  566. }
  567. func (ep *endpoint) updateParentHosts() error {
  568. ep.Lock()
  569. container := ep.container
  570. network := ep.network
  571. ep.Unlock()
  572. if container == nil {
  573. return ErrNoContainer{}
  574. }
  575. for _, update := range container.config.parentUpdates {
  576. network.Lock()
  577. pep, ok := network.endpoints[types.UUID(update.eid)]
  578. if !ok {
  579. network.Unlock()
  580. continue
  581. }
  582. network.Unlock()
  583. pep.Lock()
  584. pContainer := pep.container
  585. pep.Unlock()
  586. if pContainer != nil {
  587. if err := etchosts.Update(pContainer.config.hostsPath, update.ip, update.name); err != nil {
  588. return err
  589. }
  590. }
  591. }
  592. return nil
  593. }
  594. func (ep *endpoint) updateDNS(resolvConf []byte) error {
  595. ep.Lock()
  596. container := ep.container
  597. network := ep.network
  598. ep.Unlock()
  599. if container == nil {
  600. return ErrNoContainer{}
  601. }
  602. oldHash := []byte{}
  603. hashFile := container.config.resolvConfPath + ".hash"
  604. resolvBytes, err := ioutil.ReadFile(container.config.resolvConfPath)
  605. if err != nil {
  606. if !os.IsNotExist(err) {
  607. return err
  608. }
  609. } else {
  610. oldHash, err = ioutil.ReadFile(hashFile)
  611. if err != nil {
  612. if !os.IsNotExist(err) {
  613. return err
  614. }
  615. oldHash = []byte{}
  616. }
  617. }
  618. curHash, err := ioutils.HashData(bytes.NewReader(resolvBytes))
  619. if err != nil {
  620. return err
  621. }
  622. if string(oldHash) != "" && curHash != string(oldHash) {
  623. // Seems the user has changed the container resolv.conf since the last time
  624. // we checked so return without doing anything.
  625. return nil
  626. }
  627. // replace any localhost/127.* and remove IPv6 nameservers if IPv6 disabled.
  628. resolvConf, _ = resolvconf.FilterResolvDNS(resolvConf, network.enableIPv6)
  629. newHash, err := ioutils.HashData(bytes.NewReader(resolvConf))
  630. if err != nil {
  631. return err
  632. }
  633. // for atomic updates to these files, use temporary files with os.Rename:
  634. dir := path.Dir(container.config.resolvConfPath)
  635. tmpHashFile, err := ioutil.TempFile(dir, "hash")
  636. if err != nil {
  637. return err
  638. }
  639. tmpResolvFile, err := ioutil.TempFile(dir, "resolv")
  640. if err != nil {
  641. return err
  642. }
  643. // Change the perms to 0644 since ioutil.TempFile creates it by default as 0600
  644. if err := os.Chmod(tmpResolvFile.Name(), 0644); err != nil {
  645. return err
  646. }
  647. // write the updates to the temp files
  648. if err = ioutil.WriteFile(tmpHashFile.Name(), []byte(newHash), 0644); err != nil {
  649. return err
  650. }
  651. if err = ioutil.WriteFile(tmpResolvFile.Name(), resolvConf, 0644); err != nil {
  652. return err
  653. }
  654. // rename the temp files for atomic replace
  655. if err = os.Rename(tmpHashFile.Name(), hashFile); err != nil {
  656. return err
  657. }
  658. return os.Rename(tmpResolvFile.Name(), container.config.resolvConfPath)
  659. }
  660. func copyFile(src, dst string) error {
  661. sBytes, err := ioutil.ReadFile(src)
  662. if err != nil {
  663. return err
  664. }
  665. return ioutil.WriteFile(dst, sBytes, 0644)
  666. }
  667. func (ep *endpoint) setupDNS() error {
  668. ep.Lock()
  669. container := ep.container
  670. joinInfo := ep.joinInfo
  671. ep.Unlock()
  672. if container == nil {
  673. return ErrNoContainer{}
  674. }
  675. if container.config.resolvConfPath == "" {
  676. container.config.resolvConfPath = defaultPrefix + "/" + container.id + "/resolv.conf"
  677. }
  678. dir, _ := filepath.Split(container.config.resolvConfPath)
  679. err := createBasePath(dir)
  680. if err != nil {
  681. return err
  682. }
  683. if joinInfo.resolvConfPath != "" {
  684. if err := copyFile(joinInfo.resolvConfPath, container.config.resolvConfPath); err != nil {
  685. return fmt.Errorf("could not copy source resolv.conf file %s to %s: %v", joinInfo.resolvConfPath, container.config.resolvConfPath, err)
  686. }
  687. return nil
  688. }
  689. resolvConf, err := resolvconf.Get()
  690. if err != nil {
  691. return err
  692. }
  693. if len(container.config.dnsList) > 0 ||
  694. len(container.config.dnsSearchList) > 0 {
  695. var (
  696. dnsList = resolvconf.GetNameservers(resolvConf)
  697. dnsSearchList = resolvconf.GetSearchDomains(resolvConf)
  698. )
  699. if len(container.config.dnsList) > 0 {
  700. dnsList = container.config.dnsList
  701. }
  702. if len(container.config.dnsSearchList) > 0 {
  703. dnsSearchList = container.config.dnsSearchList
  704. }
  705. return resolvconf.Build(container.config.resolvConfPath, dnsList, dnsSearchList)
  706. }
  707. return ep.updateDNS(resolvConf)
  708. }
  709. // EndpointOptionGeneric function returns an option setter for a Generic option defined
  710. // in a Dictionary of Key-Value pair
  711. func EndpointOptionGeneric(generic map[string]interface{}) EndpointOption {
  712. return func(ep *endpoint) {
  713. for k, v := range generic {
  714. ep.generic[k] = v
  715. }
  716. }
  717. }
  718. // JoinOptionPriority function returns an option setter for priority option to
  719. // be passed to endpoint Join method.
  720. func JoinOptionPriority(prio int) EndpointOption {
  721. return func(ep *endpoint) {
  722. ep.container.config.prio = prio
  723. }
  724. }
  725. // JoinOptionHostname function returns an option setter for hostname option to
  726. // be passed to endpoint Join method.
  727. func JoinOptionHostname(name string) EndpointOption {
  728. return func(ep *endpoint) {
  729. ep.container.config.hostName = name
  730. }
  731. }
  732. // JoinOptionDomainname function returns an option setter for domainname option to
  733. // be passed to endpoint Join method.
  734. func JoinOptionDomainname(name string) EndpointOption {
  735. return func(ep *endpoint) {
  736. ep.container.config.domainName = name
  737. }
  738. }
  739. // JoinOptionHostsPath function returns an option setter for hostspath option to
  740. // be passed to endpoint Join method.
  741. func JoinOptionHostsPath(path string) EndpointOption {
  742. return func(ep *endpoint) {
  743. ep.container.config.hostsPath = path
  744. }
  745. }
  746. // JoinOptionExtraHost function returns an option setter for extra /etc/hosts options
  747. // which is a name and IP as strings.
  748. func JoinOptionExtraHost(name string, IP string) EndpointOption {
  749. return func(ep *endpoint) {
  750. ep.container.config.extraHosts = append(ep.container.config.extraHosts, extraHost{name: name, IP: IP})
  751. }
  752. }
  753. // JoinOptionParentUpdate function returns an option setter for parent container
  754. // which needs to update the IP address for the linked container.
  755. func JoinOptionParentUpdate(eid string, name, ip string) EndpointOption {
  756. return func(ep *endpoint) {
  757. ep.container.config.parentUpdates = append(ep.container.config.parentUpdates, parentUpdate{eid: eid, name: name, ip: ip})
  758. }
  759. }
  760. // JoinOptionResolvConfPath function returns an option setter for resolvconfpath option to
  761. // be passed to endpoint Join method.
  762. func JoinOptionResolvConfPath(path string) EndpointOption {
  763. return func(ep *endpoint) {
  764. ep.container.config.resolvConfPath = path
  765. }
  766. }
  767. // JoinOptionDNS function returns an option setter for dns entry option to
  768. // be passed to endpoint Join method.
  769. func JoinOptionDNS(dns string) EndpointOption {
  770. return func(ep *endpoint) {
  771. ep.container.config.dnsList = append(ep.container.config.dnsList, dns)
  772. }
  773. }
  774. // JoinOptionDNSSearch function returns an option setter for dns search entry option to
  775. // be passed to endpoint Join method.
  776. func JoinOptionDNSSearch(search string) EndpointOption {
  777. return func(ep *endpoint) {
  778. ep.container.config.dnsSearchList = append(ep.container.config.dnsSearchList, search)
  779. }
  780. }
  781. // JoinOptionUseDefaultSandbox function returns an option setter for using default sandbox to
  782. // be passed to endpoint Join method.
  783. func JoinOptionUseDefaultSandbox() EndpointOption {
  784. return func(ep *endpoint) {
  785. ep.container.config.useDefaultSandBox = true
  786. }
  787. }
  788. // CreateOptionExposedPorts function returns an option setter for the container exposed
  789. // ports option to be passed to network.CreateEndpoint() method.
  790. func CreateOptionExposedPorts(exposedPorts []types.TransportPort) EndpointOption {
  791. return func(ep *endpoint) {
  792. // Defensive copy
  793. eps := make([]types.TransportPort, len(exposedPorts))
  794. copy(eps, exposedPorts)
  795. // Store endpoint label and in generic because driver needs it
  796. ep.exposedPorts = eps
  797. ep.generic[netlabel.ExposedPorts] = eps
  798. }
  799. }
  800. // CreateOptionPortMapping function returns an option setter for the mapping
  801. // ports option to be passed to network.CreateEndpoint() method.
  802. func CreateOptionPortMapping(portBindings []types.PortBinding) EndpointOption {
  803. return func(ep *endpoint) {
  804. // Store a copy of the bindings as generic data to pass to the driver
  805. pbs := make([]types.PortBinding, len(portBindings))
  806. copy(pbs, portBindings)
  807. ep.generic[netlabel.PortMap] = pbs
  808. }
  809. }
  810. // JoinOptionGeneric function returns an option setter for Generic configuration
  811. // that is not managed by libNetwork but can be used by the Drivers during the call to
  812. // endpoint join method. Container Labels are a good example.
  813. func JoinOptionGeneric(generic map[string]interface{}) EndpointOption {
  814. return func(ep *endpoint) {
  815. ep.container.config.generic = generic
  816. }
  817. }