/libmachine/host/host.go

https://gitlab.com/vectorci/machine · Go · 223 lines · 177 code · 41 blank · 5 comment · 40 complexity · 998cbf91a359faf202790ad31ca9450d MD5 · raw file

  1. package host
  2. import (
  3. "errors"
  4. "regexp"
  5. "github.com/docker/machine/libmachine/auth"
  6. "github.com/docker/machine/libmachine/drivers"
  7. "github.com/docker/machine/libmachine/engine"
  8. "github.com/docker/machine/libmachine/log"
  9. "github.com/docker/machine/libmachine/mcnerror"
  10. "github.com/docker/machine/libmachine/mcnutils"
  11. "github.com/docker/machine/libmachine/provision"
  12. "github.com/docker/machine/libmachine/provision/pkgaction"
  13. "github.com/docker/machine/libmachine/provision/serviceaction"
  14. "github.com/docker/machine/libmachine/ssh"
  15. "github.com/docker/machine/libmachine/state"
  16. "github.com/docker/machine/libmachine/swarm"
  17. )
  18. var (
  19. validHostNamePattern = regexp.MustCompile(`^[a-zA-Z0-9][a-zA-Z0-9\-\.]*$`)
  20. errMachineMustBeRunningForUpgrade = errors.New("Error: machine must be running to upgrade.")
  21. stdSSHClientCreator SSHClientCreator = &StandardSSHClientCreator{}
  22. )
  23. type SSHClientCreator interface {
  24. CreateSSHClient(d drivers.Driver) (ssh.Client, error)
  25. }
  26. type StandardSSHClientCreator struct {
  27. drivers.Driver
  28. }
  29. func SetSSHClientCreator(creator SSHClientCreator) {
  30. stdSSHClientCreator = creator
  31. }
  32. type Host struct {
  33. ConfigVersion int
  34. Driver drivers.Driver
  35. DriverName string
  36. HostOptions *Options
  37. Name string
  38. RawDriver []byte `json:"-"`
  39. }
  40. type Options struct {
  41. Driver string
  42. Memory int
  43. Disk int
  44. EngineOptions *engine.Options
  45. SwarmOptions *swarm.Options
  46. AuthOptions *auth.Options
  47. }
  48. type Metadata struct {
  49. ConfigVersion int
  50. DriverName string
  51. HostOptions Options
  52. }
  53. func ValidateHostName(name string) bool {
  54. return validHostNamePattern.MatchString(name)
  55. }
  56. func (h *Host) RunSSHCommand(command string) (string, error) {
  57. return drivers.RunSSHCommandFromDriver(h.Driver, command)
  58. }
  59. func (h *Host) CreateSSHClient() (ssh.Client, error) {
  60. return stdSSHClientCreator.CreateSSHClient(h.Driver)
  61. }
  62. func (creator *StandardSSHClientCreator) CreateSSHClient(d drivers.Driver) (ssh.Client, error) {
  63. addr, err := d.GetSSHHostname()
  64. if err != nil {
  65. return &ssh.ExternalClient{}, err
  66. }
  67. port, err := d.GetSSHPort()
  68. if err != nil {
  69. return &ssh.ExternalClient{}, err
  70. }
  71. auth := &ssh.Auth{}
  72. if d.GetSSHKeyPath() != "" {
  73. auth.Keys = []string{d.GetSSHKeyPath()}
  74. }
  75. return ssh.NewClient(d.GetSSHUsername(), addr, port, auth)
  76. }
  77. func (h *Host) runActionForState(action func() error, desiredState state.State) error {
  78. if drivers.MachineInState(h.Driver, desiredState)() {
  79. return mcnerror.ErrHostAlreadyInState{
  80. Name: h.Name,
  81. State: desiredState,
  82. }
  83. }
  84. if err := action(); err != nil {
  85. return err
  86. }
  87. return mcnutils.WaitFor(drivers.MachineInState(h.Driver, desiredState))
  88. }
  89. func (h *Host) WaitForDocker() error {
  90. provisioner, err := provision.DetectProvisioner(h.Driver)
  91. if err != nil {
  92. return err
  93. }
  94. return provision.WaitForDocker(provisioner, engine.DefaultPort)
  95. }
  96. func (h *Host) Start() error {
  97. log.Infof("Starting %q...", h.Name)
  98. if err := h.runActionForState(h.Driver.Start, state.Running); err != nil {
  99. return err
  100. }
  101. log.Infof("Machine %q was started.", h.Name)
  102. return h.WaitForDocker()
  103. }
  104. func (h *Host) Stop() error {
  105. log.Infof("Stopping %q...", h.Name)
  106. if err := h.runActionForState(h.Driver.Stop, state.Stopped); err != nil {
  107. return err
  108. }
  109. log.Infof("Machine %q was stopped.", h.Name)
  110. return nil
  111. }
  112. func (h *Host) Kill() error {
  113. log.Infof("Killing %q...", h.Name)
  114. if err := h.runActionForState(h.Driver.Kill, state.Stopped); err != nil {
  115. return err
  116. }
  117. log.Infof("Machine %q was killed.", h.Name)
  118. return nil
  119. }
  120. func (h *Host) Restart() error {
  121. log.Infof("Restarting %q...", h.Name)
  122. if drivers.MachineInState(h.Driver, state.Stopped)() {
  123. if err := h.Start(); err != nil {
  124. return err
  125. }
  126. } else if drivers.MachineInState(h.Driver, state.Running)() {
  127. if err := h.Driver.Restart(); err != nil {
  128. return err
  129. }
  130. if err := mcnutils.WaitFor(drivers.MachineInState(h.Driver, state.Running)); err != nil {
  131. return err
  132. }
  133. }
  134. return h.WaitForDocker()
  135. }
  136. func (h *Host) Upgrade() error {
  137. machineState, err := h.Driver.GetState()
  138. if err != nil {
  139. return err
  140. }
  141. if machineState != state.Running {
  142. return errMachineMustBeRunningForUpgrade
  143. }
  144. provisioner, err := provision.DetectProvisioner(h.Driver)
  145. if err != nil {
  146. return err
  147. }
  148. log.Info("Upgrading docker...")
  149. if err := provisioner.Package("docker", pkgaction.Upgrade); err != nil {
  150. return err
  151. }
  152. log.Info("Restarting docker...")
  153. return provisioner.Service("docker", serviceaction.Restart)
  154. }
  155. func (h *Host) URL() (string, error) {
  156. return h.Driver.GetURL()
  157. }
  158. func (h *Host) AuthOptions() *auth.Options {
  159. if h.HostOptions == nil {
  160. return nil
  161. }
  162. return h.HostOptions.AuthOptions
  163. }
  164. func (h *Host) ConfigureAuth() error {
  165. provisioner, err := provision.DetectProvisioner(h.Driver)
  166. if err != nil {
  167. return err
  168. }
  169. // TODO: This is kind of a hack (or is it? I'm not really sure until
  170. // we have more clearly defined outlook on what the responsibilities
  171. // and modularity of the provisioners should be).
  172. //
  173. // Call provision to re-provision the certs properly.
  174. return provisioner.Provision(swarm.Options{}, *h.HostOptions.AuthOptions, *h.HostOptions.EngineOptions)
  175. }
  176. func (h *Host) Provision() error {
  177. provisioner, err := provision.DetectProvisioner(h.Driver)
  178. if err != nil {
  179. return err
  180. }
  181. return provisioner.Provision(*h.HostOptions.SwarmOptions, *h.HostOptions.AuthOptions, *h.HostOptions.EngineOptions)
  182. }