client_factory.go 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. package docker
  2. import (
  3. "fmt"
  4. "sync"
  5. "golang.org/x/net/context"
  6. dockerclient "github.com/docker/engine-api/client"
  7. composeClient "github.com/docker/libcompose/docker/client"
  8. "github.com/docker/libcompose/project"
  9. "github.com/rancher/os/config"
  10. "github.com/rancher/os/log"
  11. "github.com/rancher/os/util"
  12. )
  13. type ClientFactory struct {
  14. userClient dockerclient.APIClient
  15. systemClient dockerclient.APIClient
  16. userOnce sync.Once
  17. systemOnce sync.Once
  18. }
  19. func NewClientFactory(opts composeClient.Options) (project.ClientFactory, error) {
  20. userOpts := opts
  21. systemOpts := opts
  22. userOpts.Host = config.DockerHost
  23. systemOpts.Host = config.SystemDockerHost
  24. userClient, err := composeClient.Create(userOpts)
  25. if err != nil {
  26. return nil, err
  27. }
  28. systemClient, err := composeClient.Create(systemOpts)
  29. if err != nil {
  30. return nil, err
  31. }
  32. return &ClientFactory{
  33. userClient: userClient,
  34. systemClient: systemClient,
  35. }, nil
  36. }
  37. func (c *ClientFactory) Create(service project.Service) dockerclient.APIClient {
  38. if IsSystemContainer(service.Config()) {
  39. waitFor(&c.systemOnce, c.systemClient, config.SystemDockerHost)
  40. return c.systemClient
  41. }
  42. waitFor(&c.userOnce, c.userClient, config.DockerHost)
  43. return c.userClient
  44. }
  45. func waitFor(once *sync.Once, client dockerclient.APIClient, endpoint string) {
  46. once.Do(func() {
  47. err := ClientOK(endpoint, func() bool {
  48. _, err := client.Info(context.Background())
  49. return err == nil
  50. })
  51. if err != nil {
  52. panic(err.Error())
  53. }
  54. })
  55. }
  56. func ClientOK(endpoint string, test func() bool) error {
  57. backoff := util.Backoff{}
  58. defer backoff.Close()
  59. var err error
  60. retry := false
  61. for ok := range backoff.Start() {
  62. if !ok {
  63. err = fmt.Errorf("Timeout waiting for Docker at %s", endpoint)
  64. break
  65. }
  66. if test() {
  67. break
  68. }
  69. retry = true
  70. log.Infof("Waiting for Docker at %s", endpoint)
  71. }
  72. if err != nil {
  73. return err
  74. }
  75. if retry {
  76. log.Infof("Connected to Docker at %s", endpoint)
  77. }
  78. return nil
  79. }