weave.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. package app
  2. import (
  3. "fmt"
  4. "net"
  5. "strings"
  6. fsouza "github.com/fsouza/go-dockerclient"
  7. "github.com/weaveworks/common/backoff"
  8. )
  9. // Default values for weave app integration
  10. const (
  11. DefaultHostname = "scope.weave.local."
  12. DefaultWeaveURL = "http://127.0.0.1:6784"
  13. DefaultContainerName = "weavescope"
  14. )
  15. // WeavePublisher is a thing which periodically registers this app with WeaveDNS.
  16. type WeavePublisher struct {
  17. containerName string
  18. hostname string
  19. dockerClient DockerClient
  20. weaveClient WeaveClient
  21. backoff backoff.Interface
  22. interfaces InterfaceFunc
  23. }
  24. // DockerClient is the little bit of the docker client we need.
  25. type DockerClient interface {
  26. ListContainers(fsouza.ListContainersOptions) ([]fsouza.APIContainers, error)
  27. }
  28. // WeaveClient is the little bit of the weave clent we need.
  29. type WeaveClient interface {
  30. AddDNSEntry(hostname, containerid string, ip net.IP) error
  31. Expose() error
  32. }
  33. // Interface is because net.Interface isn't mockable.
  34. type Interface struct {
  35. Name string
  36. Addrs []net.Addr
  37. }
  38. // InterfaceFunc is the type of Interfaces()
  39. type InterfaceFunc func() ([]Interface, error)
  40. // Interfaces returns the list of Interfaces on the machine.
  41. func Interfaces() ([]Interface, error) {
  42. ifaces, err := net.Interfaces()
  43. if err != nil {
  44. return nil, err
  45. }
  46. result := []Interface{}
  47. for _, i := range ifaces {
  48. addrs, err := i.Addrs()
  49. if err != nil {
  50. continue
  51. }
  52. result = append(result, Interface{
  53. Name: i.Name,
  54. Addrs: addrs,
  55. })
  56. }
  57. return result, nil
  58. }
  59. // NewWeavePublisher makes a new Weave.
  60. func NewWeavePublisher(weaveClient WeaveClient, dockerClient DockerClient, interfaces InterfaceFunc, hostname, containerName string) *WeavePublisher {
  61. w := &WeavePublisher{
  62. containerName: containerName,
  63. hostname: hostname,
  64. dockerClient: dockerClient,
  65. weaveClient: weaveClient,
  66. interfaces: interfaces,
  67. }
  68. w.backoff = backoff.New(w.updateDNS, "updating weaveDNS")
  69. go w.backoff.Start()
  70. return w
  71. }
  72. // Stop the Weave.
  73. func (w *WeavePublisher) Stop() {
  74. w.backoff.Stop()
  75. }
  76. func (w *WeavePublisher) updateDNS() (bool, error) {
  77. // 0. expose this host
  78. if err := w.weaveClient.Expose(); err != nil {
  79. return false, err
  80. }
  81. // 1. work out my IP addresses
  82. ifaces, err := w.interfaces()
  83. if err != nil {
  84. return false, err
  85. }
  86. ips := []net.IP{}
  87. for _, i := range ifaces {
  88. if strings.HasPrefix(i.Name, "lo") ||
  89. strings.HasPrefix(i.Name, "docker") ||
  90. strings.HasPrefix(i.Name, "veth") {
  91. continue
  92. }
  93. for _, addr := range i.Addrs {
  94. var ip net.IP
  95. switch v := addr.(type) {
  96. case *net.IPAddr:
  97. ip = v.IP
  98. case *net.IPNet:
  99. ip = v.IP
  100. }
  101. if ip != nil && ip.To4() != nil {
  102. ips = append(ips, ip)
  103. }
  104. }
  105. }
  106. // 2. work out my container name
  107. containers, err := w.dockerClient.ListContainers(fsouza.ListContainersOptions{})
  108. if err != nil {
  109. return false, err
  110. }
  111. containerID := ""
  112. outer:
  113. for _, container := range containers {
  114. for _, name := range container.Names {
  115. if name == "/"+w.containerName {
  116. containerID = container.ID
  117. break outer
  118. }
  119. }
  120. }
  121. if containerID == "" {
  122. return false, fmt.Errorf("Container %s not found", w.containerName)
  123. }
  124. // 3. Register these with weave dns
  125. for _, ip := range ips {
  126. if err := w.weaveClient.AddDNSEntry(w.hostname, containerID, ip); err != nil {
  127. return false, err
  128. }
  129. }
  130. return false, nil
  131. }