1package provision 2 3import ( 4 "fmt" 5 6 "github.com/docker/machine/libmachine/auth" 7 "github.com/docker/machine/libmachine/drivers" 8 "github.com/docker/machine/libmachine/engine" 9 "github.com/docker/machine/libmachine/log" 10 "github.com/docker/machine/libmachine/provision/pkgaction" 11 "github.com/docker/machine/libmachine/provision/serviceaction" 12 "github.com/docker/machine/libmachine/swarm" 13) 14 15var ( 16 provisioners = make(map[string]*RegisteredProvisioner) 17 detector Detector = &StandardDetector{} 18) 19 20type SSHCommander interface { 21 // Short-hand for accessing an SSH command from the driver. 22 SSHCommand(args string) (string, error) 23} 24 25type Detector interface { 26 DetectProvisioner(d drivers.Driver) (Provisioner, error) 27} 28 29type StandardDetector struct{} 30 31func SetDetector(newDetector Detector) { 32 detector = newDetector 33} 34 35// Provisioner defines distribution specific actions 36type Provisioner interface { 37 fmt.Stringer 38 SSHCommander 39 40 // Create the files for the daemon to consume configuration settings (return struct of content and path) 41 GenerateDockerOptions(dockerPort int) (*DockerOptions, error) 42 43 // Get the directory where the settings files for docker are to be found 44 GetDockerOptionsDir() string 45 46 // Return the auth options used to configure remote connection for the daemon. 47 GetAuthOptions() auth.Options 48 49 // Get the swarm options associated with this host. 50 GetSwarmOptions() swarm.Options 51 52 // Run a package action e.g. install 53 Package(name string, action pkgaction.PackageAction) error 54 55 // Get Hostname 56 Hostname() (string, error) 57 58 // Set hostname 59 SetHostname(hostname string) error 60 61 // Figure out if this is the right provisioner to use based on /etc/os-release info 62 CompatibleWithHost() bool 63 64 // Do the actual provisioning piece: 65 // 1. Set the hostname on the instance. 66 // 2. Install Docker if it is not present. 67 // 3. Configure the daemon to accept connections over TLS. 68 // 4. Copy the needed certificates to the server and local config dir. 69 // 5. Configure / activate swarm if applicable. 70 Provision(swarmOptions swarm.Options, authOptions auth.Options, engineOptions engine.Options) error 71 72 // Perform action on a named service e.g. stop 73 Service(name string, action serviceaction.ServiceAction) error 74 75 // Get the driver which is contained in the provisioner. 76 GetDriver() drivers.Driver 77 78 // Set the OS Release info depending on how it's represented 79 // internally 80 SetOsReleaseInfo(info *OsRelease) 81 82 // Get the OS Release info for the current provisioner 83 GetOsReleaseInfo() (*OsRelease, error) 84} 85 86// RegisteredProvisioner creates a new provisioner 87type RegisteredProvisioner struct { 88 New func(d drivers.Driver) Provisioner 89} 90 91func Register(name string, p *RegisteredProvisioner) { 92 provisioners[name] = p 93} 94 95func DetectProvisioner(d drivers.Driver) (Provisioner, error) { 96 return detector.DetectProvisioner(d) 97} 98 99func (detector StandardDetector) DetectProvisioner(d drivers.Driver) (Provisioner, error) { 100 log.Info("Waiting for SSH to be available...") 101 if err := drivers.WaitForSSH(d); err != nil { 102 return nil, err 103 } 104 105 log.Info("Detecting the provisioner...") 106 107 osReleaseOut, err := drivers.RunSSHCommandFromDriver(d, "cat /etc/os-release") 108 if err != nil { 109 return nil, fmt.Errorf("Error getting SSH command: %s", err) 110 } 111 112 osReleaseInfo, err := NewOsRelease([]byte(osReleaseOut)) 113 if err != nil { 114 return nil, fmt.Errorf("Error parsing /etc/os-release file: %s", err) 115 } 116 117 for _, p := range provisioners { 118 provisioner := p.New(d) 119 provisioner.SetOsReleaseInfo(osReleaseInfo) 120 121 if provisioner.CompatibleWithHost() { 122 log.Debugf("found compatible host: %s", osReleaseInfo.ID) 123 return provisioner, nil 124 } 125 } 126 127 return nil, ErrDetectionFailed 128} 129