func getOrCreateHostOnlyNetwork(hostIP net.IP, netmask net.IPMask, nets map[string]*hostOnlyNetwork, vbox VBoxManager) (*hostOnlyNetwork, error) { // Search for an existing host-only adapter. hostOnlyAdapter := getHostOnlyAdapter(nets, hostIP, netmask) if hostOnlyAdapter != nil { return hostOnlyAdapter, nil } // No existing host-only adapter found. Create a new one. _, err := createHostonlyAdapter(vbox) if err != nil { // Sometimes the host-only adapter fails to create. See https://www.virtualbox.org/ticket/14040 // BUT, it is created in fact! So let's wait until it appears last in the list log.Warnf("Creating a new host-only adapter produced an error: %s", err) log.Warn("This is a known VirtualBox bug. Let's try to recover anyway...") } // It can take some time for an adapter to appear. Let's poll. hostOnlyAdapter, err = waitForNewHostOnlyNetwork(nets, vbox) if err != nil { // Sometimes, Vbox says it created it but then it cannot be found... return nil, errNewHostOnlyAdapterNotVisible } log.Warnf("Found a new host-only adapter: %q", hostOnlyAdapter.Name) hostOnlyAdapter.IPv4.IP = hostIP hostOnlyAdapter.IPv4.Mask = netmask if err := hostOnlyAdapter.Save(vbox); err != nil { return nil, err } return hostOnlyAdapter, nil }
func (d *Driver) Start() error { log.Debugf("Starting VM %s", d.MachineName) d.validateVMRef() err := d.VM.Create() if err != nil { log.Warnf("Failed to start: %s", err) return err } // They wont start immediately time.Sleep(5 * time.Second) for i := 0; i < 90; i++ { time.Sleep(time.Second) ip, _ := d.GetIP() if ip != "" { // Add a second to let things settle time.Sleep(time.Second) return nil } log.Debugf("Waiting for the VM to come up... %d", i) } log.Warnf("Unable to determine VM's IP address, did it fail to boot?") return err }
func (d *Driver) getIPByMacFromSettings(mac string) (string, error) { network, err := d.conn.LookupNetworkByName(d.PrivateNetwork) if err != nil { log.Warnf("Failed to find network: %s", err) return "", err } bridge_name, err := network.GetBridgeName() if err != nil { log.Warnf("Failed to get network bridge: %s", err) return "", err } statusFile := fmt.Sprintf(dnsmasqStatus, bridge_name) data, err := ioutil.ReadFile(statusFile) type Lease struct { Ip_address string `json:"ip-address"` Mac_address string `json:"mac-address"` // Other unused fields omitted } var s []Lease err = json.Unmarshal(data, &s) if err != nil { log.Warnf("Failed to decode dnsmasq lease status: %s", err) return "", err } for _, value := range s { if strings.ToLower(value.Mac_address) == strings.ToLower(mac) { log.Debugf("IP address: %s", value.Ip_address) return value.Ip_address, nil } } return "", nil }
// closeAll - cleanup sessions on the OV and ICSP appliances func closeAll(d *Driver) { err := d.ClientOV.SessionLogout() if err != nil { log.Warnf("OV Session Logout : %s", err) } err = d.ClientICSP.SessionLogout() if err != nil { log.Warnf("ICSP Session Logout : %s", err) } }
// removeOrphanDHCPServers removed the DHCP servers linked to no host-only adapter func removeOrphanDHCPServers(vbox VBoxManager) error { dhcps, err := listDHCPServers(vbox) if err != nil { return err } if len(dhcps) == 0 { return nil } nets, err := listHostOnlyAdapters(vbox) if err != nil { return err } for name := range dhcps { if strings.HasPrefix(name, dhcpPrefix) { if _, present := nets[name]; !present { if err := vbox.vbm("dhcpserver", "remove", "--netname", name); err != nil { log.Warnf("Unable to remove orphan dhcp server %q: %s", name, err) } } } } return nil }
// Submit desired power state and wait // Most of our concurrency will happen in PowerExecutor func (pt *PowerTask) PowerExecutor(s PowerState) error { currenttime := 0 pt.State = P_UKNOWN pt.ResetTask() go pt.SubmitPowerState(s) for !pt.TaskIsDone && (currenttime < pt.Timeout) { if err := pt.GetCurrentTaskStatus(); err != nil { return err } if pt.URI != "" && T_COMPLETED.Equal(pt.TaskState) { pt.TaskIsDone = true } if pt.URI != "" { log.Debugf("Waiting to set power state %s for blade %s, %s", s, pt.Blade.Name) log.Infof("Working on power state,%d%%, %s.", pt.ComputedPercentComplete, pt.TaskStatus) } else { log.Info("Working on power state.") } // wait time before next check time.Sleep(time.Millisecond * (1000 * pt.WaitTime)) // wait 10sec before checking the status again currenttime++ } if !(currenttime < pt.Timeout) { log.Warnf("Power %s state timed out for %s.", s, pt.Blade.Name) } log.Infof("Power Task Execution Completed") return nil }
// get current power state func (pt *PowerTask) GetCurrentPowerState() error { // Quick check to make sure we have a proper hardware blade if pt.Blade.URI.IsNil() { pt.State = P_UKNOWN return errors.New("Can't get power on blade without hardware") } // get the latest state based on current blade uri b, err := pt.Blade.Client.GetServerHardware(pt.Blade.URI) if err != nil { return err } log.Debugf("GetCurrentPowerState() blade -> %+v", b) // Set the current state of the blade as a constant if P_OFF.Equal(b.PowerState) { pt.State = P_OFF } else if P_ON.Equal(b.PowerState) { pt.State = P_ON } else { log.Warnf("Un-known power state detected %s, for %s.", b.PowerState, b.Name) pt.State = P_UKNOWN } // Reassign the current blade and state of that blade pt.Blade = b return nil }
func (c *RPCClientDriver) GetSSHPassword() string { sshPassword, err := c.rpcStringCall(GetSSHPasswordMethod) if err != nil { log.Warnf("Error attempting call to get SSH password: %s", err) } return sshPassword }
func (c *RPCClientDriver) GetOS() string { OS, err := c.rpcStringCall(GetOSMethod) if err != nil { log.Warnf("Error attempting call to get OS: %s", err) } return OS }
func (d *Driver) PreCreateCheck() error { conn, err := d.getConn() if err != nil { return err } // TODO We could look at conn.GetCapabilities() // parse the XML, and look for kvm log.Debug("About to check libvirt version") // TODO might want to check minimum version _, err = conn.GetLibVersion() if err != nil { log.Warnf("Unable to get libvirt version") return err } err = d.validatePrivateNetwork() if err != nil { return err } err = d.validateNetwork(d.Network) if err != nil { return err } // Others...? return nil }
func (d *Driver) configureTags(tagGroups string) error { tags := []*ec2.Tag{} tags = append(tags, &ec2.Tag{ Key: aws.String("Name"), Value: &d.MachineName, }) if tagGroups != "" { t := strings.Split(tagGroups, ",") if len(t) > 0 && len(t)%2 != 0 { log.Warnf("Tags are not key value in pairs. %d elements found", len(t)) } for i := 0; i < len(t)-1; i += 2 { tags = append(tags, &ec2.Tag{ Key: &t[i], Value: &t[i+1], }) } } _, err := d.getClient().CreateTags(&ec2.CreateTagsInput{ Resources: []*string{&d.InstanceId}, Tags: tags, }) if err != nil { return err } return nil }
func (d *Driver) Stop() error { log.Debugf("Stopping VM %s", d.MachineName) d.validateVMRef() s, err := d.GetState() if err != nil { return err } if s != state.Stopped { err := d.VM.DestroyFlags(libvirt.VIR_DOMAIN_DESTROY_GRACEFUL) if err != nil { log.Warnf("Failed to gracefully shutdown VM") return err } for i := 0; i < 90; i++ { time.Sleep(time.Second) s, _ := d.GetState() log.Debugf("VM state: %s", s) if s == state.Stopped { return nil } } return errors.New("VM Failed to gracefully shutdown, try the kill command") } return nil }
func (b *B2dUtils) UpdateISOCache(isoURL string) error { // recreate the cache dir if it has been manually deleted if _, err := os.Stat(b.imgCachePath); os.IsNotExist(err) { log.Infof("Image cache directory does not exist, creating it at %s...", b.imgCachePath) if err := os.Mkdir(b.imgCachePath, 0700); err != nil { return err } } exists := b.exists() if isoURL != "" { if exists { // Warn that the b2d iso won't be updated if isoURL is set log.Warnf("Boot2Docker URL was explicitly set to %q at create time, so Docker Machine cannot upgrade this machine to the latest version.", isoURL) } // Non-default B2D are not cached return nil } if !exists { log.Info("No default Boot2Docker ISO found locally, downloading the latest release...") return b.DownloadLatestBoot2Docker("") } latest := b.isLatest() if !latest { log.Info("Default Boot2Docker ISO is out-of-date, downloading the latest release...") return b.DownloadLatestBoot2Docker("") } return nil }
func NewRpcClientDriver(rawDriverData []byte, driverName string) (*RpcClientDriver, error) { mcnName := "" p := localbinary.NewLocalBinaryPlugin(driverName) go func() { if err := p.Serve(); err != nil { // If we can't safely load the server, best to just // bail. log.Fatal(err) } }() addr, err := p.Address() if err != nil { return nil, fmt.Errorf("Error attempting to get plugin server address for RPC: %s", err) } rpcclient, err := rpc.DialHTTP("tcp", addr) if err != nil { return nil, err } c := &RpcClientDriver{ Client: NewInternalClient(rpcclient), heartbeatDoneCh: make(chan bool), } go func(heartbeatDoneCh <-chan bool) { for { select { case <-heartbeatDoneCh: return default: if err := c.Client.Call("RpcServerDriver.Heartbeat", struct{}{}, nil); err != nil { log.Warnf("Error attempting heartbeat call to plugin server: %s", err) } time.Sleep(heartbeatInterval) } } }(c.heartbeatDoneCh) var version int if err := c.Client.Call("RpcServerDriver.GetVersion", struct{}{}, &version); err != nil { return nil, err } log.Debug("Using API Version ", version) if err := c.SetConfigRaw(rawDriverData); err != nil { return nil, err } mcnName = c.GetMachineName() p.MachineName = mcnName c.Client.MachineName = mcnName c.plugin = p return c, nil }
func (c *RpcClientDriver) GetSSHPassword() string { password, err := c.rpcStringCall("RpcServerDriver.GetSSHPassword") if err != nil { log.Warnf("Error attempting call to get SSH password: %s", err) } return password }
func (c *RPCClientDriver) GlobalArtifactPath() string { globalArtifactPath, err := c.rpcStringCall("RPCServerDriver.GlobalArtifactPath") if err != nil { log.Warnf("Error attempting call to get GlobalArtifactPath: %s", err) } return globalArtifactPath }
func (c *RPCClientDriver) GetSSHUsername() string { username, err := c.rpcStringCall("RPCServerDriver.GetSSHUsername") if err != nil { log.Warnf("Error attempting call to get SSH username: %s", err) } return username }
// GetSSHKeyPath returns the key path // TODO: This method doesn't even make sense to have with RPC. func (c *RPCClientDriver) GetSSHKeyPath() string { path, err := c.rpcStringCall("RPCServerDriver.GetSSHKeyPath") if err != nil { log.Warnf("Error attempting call to get SSH key path: %s", err) } return path }
func (c *RPCClientDriver) GetMachineName() string { name, err := c.rpcStringCall("RPCServerDriver.GetMachineName") if err != nil { log.Warnf("Error attempting call to get machine name: %s", err) } return name }
// DriverName returns the name of the driver func (c *RPCClientDriver) DriverName() string { driverName, err := c.rpcStringCall("RPCServerDriver.DriverName") if err != nil { log.Warnf("Error attempting call to get driver name: %s", err) } return driverName }
func (*b2dReleaseGetter) download(dir, file, isoURL string) error { u, err := url.Parse(isoURL) var src io.ReadCloser if u.Scheme == "file" || u.Scheme == "" { s, err := os.Open(u.Path) if err != nil { return err } src = s } else { client := getClient() s, err := client.Get(isoURL) if err != nil { return err } src = &ReaderWithProgress{ ReadCloser: s.Body, out: os.Stdout, expectedLength: s.ContentLength, } } defer src.Close() // Download to a temp file first then rename it to avoid partial download. f, err := ioutil.TempFile(dir, file+".tmp") if err != nil { return err } defer func() { if err := removeFileIfExists(f.Name()); err != nil { log.Warnf("Error removing file: %s", err) } }() if _, err := io.Copy(f, src); err != nil { return err } if err := f.Close(); err != nil { return err } // Dest is the final path of the boot2docker.iso file. dest := filepath.Join(dir, file) // Windows can't rename in place, so remove the old file before // renaming the temporary downloaded file. if err := removeFileIfExists(dest); err != nil { return err } return os.Rename(f.Name(), dest) }
func stream(scanner *bufio.Scanner, streamOutCh chan<- string) { for scanner.Scan() { line := scanner.Text() if err := scanner.Err(); err != nil { log.Warnf("Scanning stream: %s", err) } streamOutCh <- strings.Trim(line, "\n") } }
func (d *Driver) Create() error { b2dutils := mcnutils.NewB2dUtils(d.StorePath) if err := b2dutils.CopyIsoToMachineDir(d.Boot2DockerURL, d.MachineName); err != nil { return err } log.Infof("Creating SSH key...") if err := ssh.GenerateSSHKey(d.GetSSHKeyPath()); err != nil { return err } if err := os.MkdirAll(d.ResolveStorePath("."), 0755); err != nil { return err } // Libvirt typically runs as a deprivileged service account and // needs the execute bit set for directories that contain disks for dir := d.ResolveStorePath("."); dir != "/"; dir = filepath.Dir(dir) { log.Debugf("Verifying executable bit set on %s", dir) info, err := os.Stat(dir) if err != nil { return err } mode := info.Mode() if mode&0001 != 1 { log.Debugf("Setting executable bit set on %s", dir) mode |= 0001 os.Chmod(dir, mode) } } log.Debugf("Creating VM data disk...") if err := d.generateDiskImage(d.DiskSize); err != nil { return err } log.Debugf("Defining VM...") tmpl, err := template.New("domain").Parse(domainXMLTemplate) if err != nil { return err } var xml bytes.Buffer err = tmpl.Execute(&xml, d) if err != nil { return err } vm, err := d.conn.DomainDefineXML(xml.String()) if err != nil { log.Warnf("Failed to create the VM: %s", err) return err } d.VM = &vm d.vmLoaded = true return d.Start() }
func (provisioner *SUSEProvisioner) dockerDaemonResponding() bool { if _, err := provisioner.SSHCommand("sudo docker version"); err != nil { log.Warnf("Error getting SSH command to check if the daemon is up: %s", err) return false } // The daemon is up if the command worked. Carry on. return true }
func (c *RPCClientDriver) LocalArtifactPath(file string) string { var path string if err := c.Client.Call("RPCServerDriver.LocalArtifactPath", file, &path); err != nil { log.Warnf("Error attempting call to get LocalArtifactPath: %s", err) } return path }
func (c *RPCClientDriver) GetCreateFlags() []mcnflag.Flag { var flags []mcnflag.Flag if err := c.Client.Call("RPCServerDriver.GetCreateFlags", struct{}{}, &flags); err != nil { log.Warnf("Error attempting call to get create flags: %s", err) } return flags }
func (c *RpcClientDriver) SSHSudo(command string) string { var escaped string if err := c.Client.Call("RpcServerDriver.SSHSudo", command, &escaped); err != nil { log.Warnf("Error attempting call to get SSHSudo: %s", err) } return escaped }
// Download boot2docker ISO image for the given tag and save it at dest. func (b *B2dUtils) DownloadISO(dir, file, isoUrl string) error { u, err := url.Parse(isoUrl) var src io.ReadCloser if u.Scheme == "file" || u.Scheme == "" { s, err := os.Open(u.Path) if err != nil { return err } src = s } else { client := getClient() s, err := client.Get(isoUrl) if err != nil { return err } src = s.Body } defer src.Close() // Download to a temp file first then rename it to avoid partial download. f, err := ioutil.TempFile(dir, file+".tmp") if err != nil { return err } defer func() { if err := removeFileIfExists(f.Name()); err != nil { log.Warnf("Error removing file: %s", err) } }() if _, err := io.Copy(f, src); err != nil { // TODO: display download progress? return err } if err := f.Close(); err != nil { return err } // Dest is the final path of the boot2docker.iso file. dest := filepath.Join(dir, file) // Windows can't rename in place, so remove the old file before // renaming the temporary downloaded file. if err := removeFileIfExists(dest); err != nil { return err } if err := os.Rename(f.Name(), dest); err != nil { return err } return nil }
func (provisioner *UbuntuProvisioner) dockerDaemonResponding() bool { docker_version_command := provisioner.Driver.SSHSudo("docker version") if _, err := provisioner.SSHCommand(docker_version_command); err != nil { log.Warnf("Error getting SSH command to check if the daemon is up: %s", err) return false } // The daemon is up if the command worked. Carry on. return true }
func generateId() string { rb := make([]byte, 10) _, err := rand.Read(rb) if err != nil { log.Warnf("Unable to generate id: %s", err) } h := md5.New() io.WriteString(h, string(rb)) return fmt.Sprintf("%x", h.Sum(nil)) }