1package provision 2 3import ( 4 "fmt" 5 "strings" 6 7 "github.com/docker/machine/libmachine/auth" 8 "github.com/docker/machine/libmachine/drivers" 9 "github.com/docker/machine/libmachine/engine" 10 "github.com/docker/machine/libmachine/log" 11 "github.com/docker/machine/libmachine/mcnutils" 12 "github.com/docker/machine/libmachine/provision/pkgaction" 13 "github.com/docker/machine/libmachine/provision/serviceaction" 14 "github.com/docker/machine/libmachine/swarm" 15) 16 17func init() { 18 Register("SUSE", &RegisteredProvisioner{ 19 New: NewSUSEProvisioner, 20 }) 21} 22 23func NewSUSEProvisioner(d drivers.Driver) Provisioner { 24 return &SUSEProvisioner{ 25 NewSystemdProvisioner("SUSE", d), 26 } 27} 28 29type SUSEProvisioner struct { 30 SystemdProvisioner 31} 32 33func (provisioner *SUSEProvisioner) CompatibleWithHost() bool { 34 ids := strings.Split(provisioner.OsReleaseInfo.IDLike, " ") 35 for _, id := range ids { 36 if id == "suse" { 37 return true 38 } 39 } 40 return false 41} 42 43func (provisioner *SUSEProvisioner) String() string { 44 return "SUSE" 45} 46 47func (provisioner *SUSEProvisioner) Package(name string, action pkgaction.PackageAction) error { 48 var packageAction string 49 50 switch action { 51 case pkgaction.Install: 52 packageAction = "in" 53 // This is an optimization that reduces the provisioning time of certain 54 // systems in a significant way. 55 // The invocation of "zypper in <pkg>" causes the download of the metadata 56 // of all the repositories that have never been refreshed or that have 57 // automatic refresh toggled and have not been refreshed recently. 58 // Refreshing the repository metadata can take quite some time and can cause 59 // longer provisioning times for machines that have been pre-optimized for 60 // docker by including all the needed packages. 61 if _, err := provisioner.SSHCommand(fmt.Sprintf("rpm -q %s", name)); err == nil { 62 log.Debugf("%s is already installed, skipping operation", name) 63 return nil 64 } 65 case pkgaction.Remove: 66 packageAction = "rm" 67 case pkgaction.Upgrade: 68 packageAction = "up" 69 } 70 71 command := fmt.Sprintf("sudo -E zypper -n %s %s", packageAction, name) 72 73 log.Debugf("zypper: action=%s name=%s", action.String(), name) 74 75 if _, err := provisioner.SSHCommand(command); err != nil { 76 return err 77 } 78 79 return nil 80} 81 82func (provisioner *SUSEProvisioner) dockerDaemonResponding() bool { 83 log.Debug("checking docker daemon") 84 85 if out, err := provisioner.SSHCommand("sudo docker version"); err != nil { 86 log.Warnf("Error getting SSH command to check if the daemon is up: %s", err) 87 log.Debugf("'sudo docker version' output:\n%s", out) 88 return false 89 } 90 91 // The daemon is up if the command worked. Carry on. 92 return true 93} 94 95func (provisioner *SUSEProvisioner) Provision(swarmOptions swarm.Options, authOptions auth.Options, engineOptions engine.Options) error { 96 provisioner.SwarmOptions = swarmOptions 97 provisioner.AuthOptions = authOptions 98 provisioner.EngineOptions = engineOptions 99 swarmOptions.Env = engineOptions.Env 100 101 // figure out the filesystem used by /var/lib/docker 102 fs, err := provisioner.SSHCommand("stat -f -c %T /var/lib/docker") 103 if err != nil { 104 // figure out the filesystem used by /var/lib 105 fs, err = provisioner.SSHCommand("stat -f -c %T /var/lib/") 106 if err != nil { 107 return err 108 } 109 } 110 graphDriver := "overlay" 111 if strings.Contains(fs, "btrfs") { 112 graphDriver = "btrfs" 113 } 114 115 storageDriver, err := decideStorageDriver(provisioner, graphDriver, engineOptions.StorageDriver) 116 if err != nil { 117 return err 118 } 119 provisioner.EngineOptions.StorageDriver = storageDriver 120 121 log.Debug("Setting hostname") 122 if err := provisioner.SetHostname(provisioner.Driver.GetMachineName()); err != nil { 123 return err 124 } 125 126 if !strings.HasPrefix(strings.ToLower(provisioner.OsReleaseInfo.ID), "opensuse") { 127 // This is a SLE machine, enable the containers module to have access 128 // to the docker packages 129 if _, err := provisioner.SSHCommand("sudo -E SUSEConnect -p sle-module-containers/12/$(uname -m) -r ''"); err != nil { 130 return fmt.Errorf( 131 "Error while adding the 'containers' module, make sure this machine is registered either against SUSE Customer Center (SCC) or to a local Subscription Management Tool (SMT): %v", 132 err) 133 } 134 } 135 136 log.Debug("Installing base packages") 137 for _, pkg := range provisioner.Packages { 138 if err := provisioner.Package(pkg, pkgaction.Install); err != nil { 139 return err 140 } 141 } 142 143 log.Debug("Installing docker") 144 if err := provisioner.Package("docker", pkgaction.Install); err != nil { 145 return err 146 } 147 148 // create symlinks for containerd, containerd-shim and optional runc. 149 // We have to do that because machine overrides the openSUSE systemd 150 // unit of docker 151 if _, err := provisioner.SSHCommand("yes no | sudo -E ln -si /usr/sbin/runc /usr/sbin/docker-runc"); err != nil { 152 return err 153 } 154 if _, err := provisioner.SSHCommand("sudo -E ln -sf /usr/sbin/containerd /usr/sbin/docker-containerd"); err != nil { 155 return err 156 } 157 if _, err := provisioner.SSHCommand("sudo -E ln -sf /usr/sbin/containerd-shim /usr/sbin/docker-containerd-shim"); err != nil { 158 return err 159 } 160 161 // Is yast2 firewall installed? 162 if _, installed := provisioner.SSHCommand("rpm -q yast2-firewall"); installed == nil { 163 // Open the firewall port required by docker 164 if _, err := provisioner.SSHCommand("sudo -E /sbin/yast2 firewall services add ipprotocol=tcp tcpport=2376 zone=EXT"); err != nil { 165 return err 166 } 167 } 168 169 log.Debug("Starting systemd docker service") 170 if err := provisioner.Service("docker", serviceaction.Start); err != nil { 171 return err 172 } 173 174 log.Debug("Waiting for docker daemon") 175 if err := mcnutils.WaitFor(provisioner.dockerDaemonResponding); err != nil { 176 return err 177 } 178 179 provisioner.AuthOptions = setRemoteAuthOptions(provisioner) 180 181 log.Debug("Configuring auth") 182 if err := ConfigureAuth(provisioner); err != nil { 183 return err 184 } 185 186 log.Debug("Configuring swarm") 187 if err := configureSwarm(provisioner, swarmOptions, provisioner.AuthOptions); err != nil { 188 return err 189 } 190 191 // enable in systemd 192 log.Debug("Enabling docker in systemd") 193 err = provisioner.Service("docker", serviceaction.Enable) 194 return err 195} 196