endpoint.go 22 KB

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