github.com/cloud-foundations/dominator@v0.0.0-20221004181915-6e4fee580046/hypervisor/manager/vm.go (about)

     1  package manager
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/rand"
     6  	"fmt"
     7  	"io"
     8  	"io/ioutil"
     9  	"net"
    10  	"net/http"
    11  	"os"
    12  	"os/exec"
    13  	"path/filepath"
    14  	"syscall"
    15  	"time"
    16  
    17  	domlib "github.com/Cloud-Foundations/Dominator/dom/lib"
    18  	hyperclient "github.com/Cloud-Foundations/Dominator/hypervisor/client"
    19  	imclient "github.com/Cloud-Foundations/Dominator/imageserver/client"
    20  	"github.com/Cloud-Foundations/Dominator/lib/errors"
    21  	"github.com/Cloud-Foundations/Dominator/lib/filesystem"
    22  	"github.com/Cloud-Foundations/Dominator/lib/filesystem/scanner"
    23  	"github.com/Cloud-Foundations/Dominator/lib/filesystem/util"
    24  	"github.com/Cloud-Foundations/Dominator/lib/filter"
    25  	"github.com/Cloud-Foundations/Dominator/lib/format"
    26  	"github.com/Cloud-Foundations/Dominator/lib/fsutil"
    27  	"github.com/Cloud-Foundations/Dominator/lib/hash"
    28  	"github.com/Cloud-Foundations/Dominator/lib/image"
    29  	"github.com/Cloud-Foundations/Dominator/lib/json"
    30  	"github.com/Cloud-Foundations/Dominator/lib/log"
    31  	"github.com/Cloud-Foundations/Dominator/lib/log/prefixlogger"
    32  	"github.com/Cloud-Foundations/Dominator/lib/mbr"
    33  	libnet "github.com/Cloud-Foundations/Dominator/lib/net"
    34  	"github.com/Cloud-Foundations/Dominator/lib/objectcache"
    35  	"github.com/Cloud-Foundations/Dominator/lib/objectserver"
    36  	objclient "github.com/Cloud-Foundations/Dominator/lib/objectserver/client"
    37  	"github.com/Cloud-Foundations/Dominator/lib/rsync"
    38  	"github.com/Cloud-Foundations/Dominator/lib/srpc"
    39  	"github.com/Cloud-Foundations/Dominator/lib/tags"
    40  	"github.com/Cloud-Foundations/Dominator/lib/verstr"
    41  	"github.com/Cloud-Foundations/Dominator/lib/wsyscall"
    42  	proto "github.com/Cloud-Foundations/Dominator/proto/hypervisor"
    43  	subproto "github.com/Cloud-Foundations/Dominator/proto/sub"
    44  	sublib "github.com/Cloud-Foundations/Dominator/sub/lib"
    45  )
    46  
    47  const (
    48  	bootlogFilename    = "bootlog"
    49  	serialSockFilename = "serial0.sock"
    50  )
    51  
    52  var (
    53  	errorNoAccessToResource = errors.New("no access to resource")
    54  )
    55  
    56  func computeSize(minimumFreeBytes, roundupPower, size uint64) uint64 {
    57  	minBytes := size + size>>3 // 12% extra for good luck.
    58  	minBytes += minimumFreeBytes
    59  	if roundupPower < 24 {
    60  		roundupPower = 24 // 16 MiB.
    61  	}
    62  	imageUnits := minBytes >> roundupPower
    63  	if imageUnits<<roundupPower < minBytes {
    64  		imageUnits++
    65  	}
    66  	return imageUnits << roundupPower
    67  }
    68  
    69  func copyData(filename string, reader io.Reader, length uint64) error {
    70  	file, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY,
    71  		fsutil.PrivateFilePerms)
    72  	if err != nil {
    73  		return err
    74  	}
    75  	defer file.Close()
    76  	if err := setVolumeSize(filename, length); err != nil {
    77  		return err
    78  	}
    79  	if reader == nil {
    80  		return nil
    81  	}
    82  	_, err = io.CopyN(file, reader, int64(length))
    83  	return err
    84  }
    85  
    86  func createTapDevice(bridge string) (*os.File, error) {
    87  	tapFile, tapName, err := libnet.CreateTapDevice()
    88  	if err != nil {
    89  		return nil, fmt.Errorf("error creating tap device: %s", err)
    90  	}
    91  	doAutoClose := true
    92  	defer func() {
    93  		if doAutoClose {
    94  			tapFile.Close()
    95  		}
    96  	}()
    97  	cmd := exec.Command("ip", "link", "set", tapName, "up")
    98  	if output, err := cmd.CombinedOutput(); err != nil {
    99  		return nil, fmt.Errorf("error upping: %s: %s", err, output)
   100  	}
   101  	cmd = exec.Command("ip", "link", "set", tapName, "master", bridge)
   102  	if output, err := cmd.CombinedOutput(); err != nil {
   103  		return nil, fmt.Errorf("error attaching: %s: %s", err, output)
   104  	}
   105  	doAutoClose = false
   106  	return tapFile, nil
   107  }
   108  
   109  func deleteFilesNotInImage(imgFS, vmFS *filesystem.FileSystem,
   110  	rootDir string, logger log.DebugLogger) error {
   111  	var totalBytes uint64
   112  	imgHashToInodesTable := imgFS.HashToInodesTable()
   113  	imgComputedFiles := make(map[string]struct{})
   114  	imgFS.ForEachFile(func(name string, inodeNumber uint64,
   115  		inode filesystem.GenericInode) error {
   116  		if _, ok := inode.(*filesystem.ComputedRegularInode); ok {
   117  			imgComputedFiles[name] = struct{}{}
   118  		}
   119  		return nil
   120  	})
   121  	for filename, inum := range vmFS.FilenameToInodeTable() {
   122  		if inode, ok := vmFS.InodeTable[inum].(*filesystem.RegularInode); ok {
   123  			if inode.Size < 1 {
   124  				continue
   125  			}
   126  			if _, isComputed := imgComputedFiles[filename]; isComputed {
   127  				continue
   128  			}
   129  			if _, inImage := imgHashToInodesTable[inode.Hash]; inImage {
   130  				continue
   131  			}
   132  			pathname := filepath.Join(rootDir, filename)
   133  			if err := os.Remove(pathname); err != nil {
   134  				return err
   135  			}
   136  			logger.Debugf(1, "pre-delete: %s\n", pathname)
   137  			totalBytes += inode.Size
   138  		}
   139  	}
   140  	logger.Debugf(0, "pre-delete: totalBytes: %s\n",
   141  		format.FormatBytes(totalBytes))
   142  	return nil
   143  }
   144  
   145  func extractKernel(volume proto.LocalVolume, extension string,
   146  	objectsGetter objectserver.ObjectsGetter, fs *filesystem.FileSystem,
   147  	bootInfo *util.BootInfoType) error {
   148  	dirent := bootInfo.KernelImageDirent
   149  	if dirent == nil {
   150  		return errors.New("no kernel image found")
   151  	}
   152  	inode, ok := dirent.Inode().(*filesystem.RegularInode)
   153  	if !ok {
   154  		return errors.New("kernel image is not a regular file")
   155  	}
   156  	inode.Size = 0
   157  	filename := filepath.Join(volume.DirectoryToCleanup, "kernel"+extension)
   158  	_, err := objectserver.LinkObject(filename, objectsGetter, inode.Hash)
   159  	if err != nil {
   160  		return err
   161  	}
   162  	dirent = bootInfo.InitrdImageDirent
   163  	if dirent != nil {
   164  		inode, ok := dirent.Inode().(*filesystem.RegularInode)
   165  		if !ok {
   166  			return errors.New("initrd image is not a regular file")
   167  		}
   168  		inode.Size = 0
   169  		filename := filepath.Join(volume.DirectoryToCleanup,
   170  			"initrd"+extension)
   171  		_, err = objectserver.LinkObject(filename, objectsGetter,
   172  			inode.Hash)
   173  		if err != nil {
   174  			return err
   175  		}
   176  	}
   177  	return nil
   178  }
   179  
   180  func maybeDrainAll(conn *srpc.Conn, request proto.CreateVmRequest) error {
   181  	if err := maybeDrainImage(conn, request.ImageDataSize); err != nil {
   182  		return err
   183  	}
   184  	if err := maybeDrainUserData(conn, request); err != nil {
   185  		return err
   186  	}
   187  	return nil
   188  }
   189  
   190  func maybeDrainImage(imageReader io.Reader, imageDataSize uint64) error {
   191  	if imageDataSize > 0 { // Drain data.
   192  		_, err := io.CopyN(ioutil.Discard, imageReader, int64(imageDataSize))
   193  		return err
   194  	}
   195  	return nil
   196  }
   197  
   198  func maybeDrainUserData(conn *srpc.Conn, request proto.CreateVmRequest) error {
   199  	if request.UserDataSize > 0 { // Drain data.
   200  		_, err := io.CopyN(ioutil.Discard, conn, int64(request.UserDataSize))
   201  		return err
   202  	}
   203  	return nil
   204  }
   205  
   206  func readData(firstByte byte, moreBytes <-chan byte) []byte {
   207  	buffer := make([]byte, 1, len(moreBytes)+1)
   208  	buffer[0] = firstByte
   209  	for {
   210  		select {
   211  		case char, ok := <-moreBytes:
   212  			if !ok {
   213  				return buffer
   214  			}
   215  			buffer = append(buffer, char)
   216  		default:
   217  			return buffer
   218  		}
   219  	}
   220  }
   221  
   222  func readOne(objectsDir string, hashVal hash.Hash, length uint64,
   223  	reader io.Reader) error {
   224  	filename := filepath.Join(objectsDir, objectcache.HashToFilename(hashVal))
   225  	dirname := filepath.Dir(filename)
   226  	if err := os.MkdirAll(dirname, dirPerms); err != nil {
   227  		return err
   228  	}
   229  	return fsutil.CopyToFile(filename, fsutil.PrivateFilePerms, reader, length)
   230  }
   231  
   232  func setVolumeSize(filename string, size uint64) error {
   233  	if err := os.Truncate(filename, int64(size)); err != nil {
   234  		return err
   235  	}
   236  	return fsutil.Fallocate(filename, size)
   237  }
   238  
   239  func (m *Manager) acknowledgeVm(ipAddr net.IP,
   240  	authInfo *srpc.AuthInformation) error {
   241  	vm, err := m.getVmLockAndAuth(ipAddr, true, authInfo, nil)
   242  	if err != nil {
   243  		return err
   244  	}
   245  	defer vm.mutex.Unlock()
   246  	vm.destroyTimer.Stop()
   247  	return nil
   248  }
   249  
   250  func (m *Manager) addVmVolumes(ipAddr net.IP, authInfo *srpc.AuthInformation,
   251  	volumeSizes []uint64) error {
   252  	vm, err := m.getVmLockAndAuth(ipAddr, true, authInfo, nil)
   253  	if err != nil {
   254  		return err
   255  	}
   256  	defer vm.mutex.Unlock()
   257  	if vm.State != proto.StateStopped {
   258  		return errors.New("VM is not stopped")
   259  	}
   260  	volumes := make([]proto.Volume, 0, len(volumeSizes))
   261  	for _, size := range volumeSizes {
   262  		volumes = append(volumes, proto.Volume{Size: size})
   263  	}
   264  	volumeDirectories, err := vm.manager.getVolumeDirectories(0, volumes,
   265  		vm.SpreadVolumes)
   266  	if err != nil {
   267  		return err
   268  	}
   269  	volumeLocations := make([]proto.LocalVolume, 0, len(volumes))
   270  	defer func() {
   271  		for _, volumeLocation := range volumeLocations {
   272  			os.Remove(volumeLocation.Filename)
   273  			os.Remove(volumeLocation.DirectoryToCleanup)
   274  		}
   275  	}()
   276  	for index, volumeDirectory := range volumeDirectories {
   277  		dirname := filepath.Join(volumeDirectory, vm.ipAddress)
   278  		filename := filepath.Join(dirname,
   279  			fmt.Sprintf("secondary-volume.%d", len(vm.Volumes)-1+index))
   280  		volumeLocation := proto.LocalVolume{
   281  			DirectoryToCleanup: dirname,
   282  			Filename:           filename,
   283  		}
   284  		if err := os.MkdirAll(dirname, dirPerms); err != nil {
   285  			return err
   286  		}
   287  		cFlags := os.O_CREATE | os.O_EXCL | os.O_RDWR
   288  		file, err := os.OpenFile(filename, cFlags, privateFilePerms)
   289  		if err != nil {
   290  			return err
   291  		} else {
   292  			file.Close()
   293  		}
   294  		if err := setVolumeSize(filename, volumeSizes[index]); err != nil {
   295  			return err
   296  		}
   297  		volumeLocations = append(volumeLocations, volumeLocation)
   298  	}
   299  	vm.VolumeLocations = append(vm.VolumeLocations, volumeLocations...)
   300  	volumeLocations = nil // Prevent cleanup. Thunderbirds are Go!
   301  	vm.Volumes = append(vm.Volumes, volumes...)
   302  	vm.writeAndSendInfo()
   303  	return nil
   304  }
   305  
   306  func (m *Manager) allocateVm(req proto.CreateVmRequest,
   307  	authInfo *srpc.AuthInformation) (*vmInfoType, error) {
   308  	if err := req.ConsoleType.CheckValid(); err != nil {
   309  		return nil, err
   310  	}
   311  	if req.MemoryInMiB < 1 {
   312  		return nil, errors.New("no memory specified")
   313  	}
   314  	if req.MilliCPUs < 1 {
   315  		return nil, errors.New("no CPUs specified")
   316  	}
   317  	subnetIDs := map[string]struct{}{req.SubnetId: {}}
   318  	for _, subnetId := range req.SecondarySubnetIDs {
   319  		if subnetId == "" {
   320  			return nil,
   321  				errors.New("cannot give unspecified secondary subnet ID")
   322  		}
   323  		if _, ok := subnetIDs[subnetId]; ok {
   324  			return nil,
   325  				fmt.Errorf("subnet: %s specified multiple times", subnetId)
   326  		}
   327  		subnetIDs[subnetId] = struct{}{}
   328  	}
   329  	address, subnetId, err := m.getFreeAddress(req.Address.IpAddress,
   330  		req.SubnetId, authInfo)
   331  	if err != nil {
   332  		return nil, err
   333  	}
   334  	addressesToFree := []proto.Address{address}
   335  	defer func() {
   336  		for _, address := range addressesToFree {
   337  			err := m.releaseAddressInPool(address)
   338  			if err != nil {
   339  				m.Logger.Println(err)
   340  			}
   341  		}
   342  	}()
   343  	var secondaryAddresses []proto.Address
   344  	for index, subnetId := range req.SecondarySubnetIDs {
   345  		var reqIpAddr net.IP
   346  		if index < len(req.SecondaryAddresses) {
   347  			reqIpAddr = req.SecondaryAddresses[index].IpAddress
   348  		}
   349  		secondaryAddress, _, err := m.getFreeAddress(reqIpAddr, subnetId,
   350  			authInfo)
   351  		if err != nil {
   352  			return nil, err
   353  		}
   354  		secondaryAddresses = append(secondaryAddresses, secondaryAddress)
   355  		addressesToFree = append(addressesToFree, secondaryAddress)
   356  	}
   357  	m.mutex.Lock()
   358  	defer m.mutex.Unlock()
   359  	if err := m.checkSufficientCPUWithLock(req.MilliCPUs); err != nil {
   360  		return nil, err
   361  	}
   362  	if err := m.checkSufficientMemoryWithLock(req.MemoryInMiB); err != nil {
   363  		return nil, err
   364  	}
   365  	var ipAddress string
   366  	if len(address.IpAddress) < 1 {
   367  		ipAddress = "0.0.0.0"
   368  	} else {
   369  		ipAddress = address.IpAddress.String()
   370  	}
   371  	vm := &vmInfoType{
   372  		LocalVmInfo: proto.LocalVmInfo{
   373  			VmInfo: proto.VmInfo{
   374  				Address:            address,
   375  				ConsoleType:        req.ConsoleType,
   376  				DestroyProtection:  req.DestroyProtection,
   377  				DisableVirtIO:      req.DisableVirtIO,
   378  				Hostname:           req.Hostname,
   379  				ImageName:          req.ImageName,
   380  				ImageURL:           req.ImageURL,
   381  				MemoryInMiB:        req.MemoryInMiB,
   382  				MilliCPUs:          req.MilliCPUs,
   383  				OwnerGroups:        req.OwnerGroups,
   384  				SpreadVolumes:      req.SpreadVolumes,
   385  				SecondaryAddresses: secondaryAddresses,
   386  				SecondarySubnetIDs: req.SecondarySubnetIDs,
   387  				State:              proto.StateStarting,
   388  				SubnetId:           subnetId,
   389  				Tags:               req.Tags,
   390  			},
   391  		},
   392  		manager:          m,
   393  		dirname:          filepath.Join(m.StateDir, "VMs", ipAddress),
   394  		ipAddress:        ipAddress,
   395  		logger:           prefixlogger.New(ipAddress+": ", m.Logger),
   396  		metadataChannels: make(map[chan<- string]struct{}),
   397  	}
   398  	m.vms[ipAddress] = vm
   399  	addressesToFree = nil
   400  	return vm, nil
   401  }
   402  
   403  func (m *Manager) becomePrimaryVmOwner(ipAddr net.IP,
   404  	authInfo *srpc.AuthInformation) error {
   405  	vm, err := m.getVmLockAndAuth(ipAddr, true, authInfo, nil)
   406  	if err != nil {
   407  		return err
   408  	}
   409  	defer vm.mutex.Unlock()
   410  	if vm.OwnerUsers[0] == authInfo.Username {
   411  		return errors.New("you already are the primary owner")
   412  	}
   413  	ownerUsers := make([]string, 1, len(vm.OwnerUsers[0]))
   414  	ownerUsers[0] = authInfo.Username
   415  	for _, user := range vm.OwnerUsers {
   416  		if user != authInfo.Username {
   417  			ownerUsers = append(ownerUsers, user)
   418  		}
   419  	}
   420  	vm.OwnerUsers = ownerUsers
   421  	vm.ownerUsers = make(map[string]struct{}, len(ownerUsers))
   422  	for _, user := range ownerUsers {
   423  		vm.ownerUsers[user] = struct{}{}
   424  	}
   425  	vm.writeAndSendInfo()
   426  	return nil
   427  }
   428  
   429  func (m *Manager) changeVmConsoleType(ipAddr net.IP,
   430  	authInfo *srpc.AuthInformation, consoleType proto.ConsoleType) error {
   431  	if err := consoleType.CheckValid(); err != nil {
   432  		return err
   433  	}
   434  	vm, err := m.getVmLockAndAuth(ipAddr, true, authInfo, nil)
   435  	if err != nil {
   436  		return err
   437  	}
   438  	defer vm.mutex.Unlock()
   439  	if vm.State != proto.StateStopped {
   440  		return errors.New("VM is not stopped")
   441  	}
   442  	vm.ConsoleType = consoleType
   443  	vm.writeAndSendInfo()
   444  	return nil
   445  }
   446  
   447  func (m *Manager) changeVmDestroyProtection(ipAddr net.IP,
   448  	authInfo *srpc.AuthInformation, destroyProtection bool) error {
   449  	vm, err := m.getVmLockAndAuth(ipAddr, true, authInfo, nil)
   450  	if err != nil {
   451  		return err
   452  	}
   453  	defer vm.mutex.Unlock()
   454  	vm.DestroyProtection = destroyProtection
   455  	vm.writeAndSendInfo()
   456  	return nil
   457  }
   458  
   459  func (m *Manager) changeVmOwnerUsers(ipAddr net.IP,
   460  	authInfo *srpc.AuthInformation, extraUsers []string) error {
   461  	vm, err := m.getVmLockAndAuth(ipAddr, true, authInfo, nil)
   462  	if err != nil {
   463  		return err
   464  	}
   465  	defer vm.mutex.Unlock()
   466  	ownerUsers := make([]string, 1, len(extraUsers)+1)
   467  	ownerUsers[0] = vm.OwnerUsers[0]
   468  	for _, user := range extraUsers {
   469  		ownerUsers = append(ownerUsers, user)
   470  	}
   471  	vm.OwnerUsers = ownerUsers
   472  	vm.ownerUsers = make(map[string]struct{}, len(ownerUsers))
   473  	for _, user := range ownerUsers {
   474  		vm.ownerUsers[user] = struct{}{}
   475  	}
   476  	vm.writeAndSendInfo()
   477  	return nil
   478  }
   479  
   480  func (m *Manager) changeVmSize(ipAddr net.IP, authInfo *srpc.AuthInformation,
   481  	memoryInMiB uint64, milliCPUs uint) error {
   482  	vm, err := m.getVmLockAndAuth(ipAddr, true, authInfo, nil)
   483  	if err != nil {
   484  		return err
   485  	}
   486  	defer vm.mutex.Unlock()
   487  	if vm.State != proto.StateStopped {
   488  		return errors.New("VM is not stopped")
   489  	}
   490  	changed := false
   491  	if memoryInMiB > 0 {
   492  		if memoryInMiB < vm.MemoryInMiB {
   493  			vm.MemoryInMiB = memoryInMiB
   494  			changed = true
   495  		} else if memoryInMiB > vm.MemoryInMiB {
   496  			m.mutex.Lock()
   497  			err := m.checkSufficientMemoryWithLock(memoryInMiB - vm.MemoryInMiB)
   498  			if err == nil {
   499  				vm.MemoryInMiB = memoryInMiB
   500  				changed = true
   501  			}
   502  			m.mutex.Unlock()
   503  			if err != nil {
   504  				return err
   505  			}
   506  		}
   507  	}
   508  	if milliCPUs > 0 {
   509  		if milliCPUs < vm.MilliCPUs {
   510  			vm.MilliCPUs = milliCPUs
   511  			changed = true
   512  		} else if milliCPUs > vm.MilliCPUs {
   513  			m.mutex.Lock()
   514  			err := m.checkSufficientCPUWithLock(milliCPUs - vm.MilliCPUs)
   515  			if err == nil {
   516  				vm.MilliCPUs = milliCPUs
   517  				changed = true
   518  			}
   519  			m.mutex.Unlock()
   520  			if err != nil {
   521  				return err
   522  			}
   523  		}
   524  	}
   525  	if changed {
   526  		vm.writeAndSendInfo()
   527  	}
   528  	return nil
   529  }
   530  
   531  func (m *Manager) changeVmTags(ipAddr net.IP, authInfo *srpc.AuthInformation,
   532  	tgs tags.Tags) error {
   533  	vm, err := m.getVmLockAndAuth(ipAddr, true, authInfo, nil)
   534  	if err != nil {
   535  		return err
   536  	}
   537  	defer vm.mutex.Unlock()
   538  	vm.Tags = tgs
   539  	vm.writeAndSendInfo()
   540  	return nil
   541  }
   542  
   543  func (m *Manager) checkVmHasHealthAgent(ipAddr net.IP) (bool, error) {
   544  	vm, err := m.getVmAndLock(ipAddr, false)
   545  	if err != nil {
   546  		return false, err
   547  	}
   548  	defer vm.mutex.RUnlock()
   549  	if vm.State != proto.StateRunning {
   550  		return false, nil
   551  	}
   552  	return vm.hasHealthAgent, nil
   553  }
   554  
   555  func (m *Manager) commitImportedVm(ipAddr net.IP,
   556  	authInfo *srpc.AuthInformation) error {
   557  	vm, err := m.getVmLockAndAuth(ipAddr, true, authInfo, nil)
   558  	if err != nil {
   559  		return err
   560  	}
   561  	defer vm.mutex.Unlock()
   562  	if !vm.Uncommitted {
   563  		return fmt.Errorf("%s is already committed", ipAddr)
   564  	}
   565  	if err := m.registerAddress(vm.Address); err != nil {
   566  		return err
   567  	}
   568  	vm.Uncommitted = false
   569  	vm.writeAndSendInfo()
   570  	return nil
   571  }
   572  
   573  func (m *Manager) connectToVmConsole(ipAddr net.IP,
   574  	authInfo *srpc.AuthInformation) (net.Conn, error) {
   575  	vm, err := m.getVmLockAndAuth(ipAddr, true, authInfo, nil)
   576  	if err != nil {
   577  		return nil, err
   578  	}
   579  	defer vm.mutex.Unlock()
   580  	if vm.State != proto.StateRunning {
   581  		return nil, errors.New("VM is not running")
   582  	}
   583  	if vm.ConsoleType != proto.ConsoleVNC {
   584  		return nil, errors.New("VNC console is not enabled")
   585  	}
   586  	console, err := net.Dial("unix", filepath.Join(vm.dirname, "vnc"))
   587  	if err != nil {
   588  		return nil, err
   589  	}
   590  	return console, nil
   591  }
   592  
   593  func (m *Manager) connectToVmSerialPort(ipAddr net.IP,
   594  	authInfo *srpc.AuthInformation,
   595  	portNumber uint) (chan<- byte, <-chan byte, error) {
   596  	if portNumber > 0 {
   597  		return nil, nil, errors.New("only one serial port is supported")
   598  	}
   599  	input := make(chan byte, 256)
   600  	output := make(chan byte, 16<<10)
   601  	vm, err := m.getVmLockAndAuth(ipAddr, true, authInfo, nil)
   602  	if err != nil {
   603  		return nil, nil, err
   604  	}
   605  	defer vm.mutex.Unlock()
   606  	if vm.State != proto.StateRunning {
   607  		return nil, nil, errors.New("VM is not running")
   608  	}
   609  	serialInput := vm.serialInput
   610  	if serialInput == nil {
   611  		return nil, nil, errors.New("no serial input device for VM")
   612  	}
   613  	if vm.serialOutput != nil {
   614  		return nil, nil, errors.New("VM already has a serial port connection")
   615  	}
   616  	vm.serialOutput = output
   617  	go func(input <-chan byte, output chan<- byte) {
   618  		for char := range input {
   619  			buffer := readData(char, input)
   620  			if _, err := serialInput.Write(buffer); err != nil {
   621  				vm.logger.Printf("error writing to serial port: %s\n", err)
   622  				break
   623  			}
   624  		}
   625  		vm.logger.Debugln(0, "input channel for console closed")
   626  		vm.mutex.Lock()
   627  		if vm.serialOutput != nil {
   628  			close(vm.serialOutput)
   629  			vm.serialOutput = nil
   630  		}
   631  		vm.mutex.Unlock()
   632  	}(input, output)
   633  	return input, output, nil
   634  }
   635  
   636  func (m *Manager) copyVm(conn *srpc.Conn, request proto.CopyVmRequest) error {
   637  	m.Logger.Debugf(1, "CopyVm(%s) starting\n", conn.Username())
   638  	hypervisor, err := srpc.DialHTTP("tcp", request.SourceHypervisor, 0)
   639  	if err != nil {
   640  		return err
   641  	}
   642  	defer hypervisor.Close()
   643  	defer func() {
   644  		req := proto.DiscardVmAccessTokenRequest{
   645  			AccessToken: request.AccessToken,
   646  			IpAddress:   request.IpAddress}
   647  		var reply proto.DiscardVmAccessTokenResponse
   648  		hypervisor.RequestReply("Hypervisor.DiscardVmAccessToken",
   649  			req, &reply)
   650  	}()
   651  	getInfoRequest := proto.GetVmInfoRequest{request.IpAddress}
   652  	var getInfoReply proto.GetVmInfoResponse
   653  	err = hypervisor.RequestReply("Hypervisor.GetVmInfo", getInfoRequest,
   654  		&getInfoReply)
   655  	if err != nil {
   656  		return err
   657  	}
   658  	switch getInfoReply.VmInfo.State {
   659  	case proto.StateStopped, proto.StateRunning:
   660  	default:
   661  		return errors.New("VM is not stopped or running")
   662  	}
   663  	accessToken := request.AccessToken
   664  	ownerUsers := make([]string, 1, len(request.OwnerUsers)+1)
   665  	ownerUsers[0] = conn.Username()
   666  	if ownerUsers[0] == "" {
   667  		return errors.New("no authentication data")
   668  	}
   669  	ownerUsers = append(ownerUsers, request.OwnerUsers...)
   670  	vmInfo := request.VmInfo
   671  	vmInfo.Address = proto.Address{}
   672  	vmInfo.SecondaryAddresses = nil
   673  	vmInfo.Uncommitted = false
   674  	vmInfo.Volumes = getInfoReply.VmInfo.Volumes
   675  	vm, err := m.allocateVm(proto.CreateVmRequest{VmInfo: vmInfo},
   676  		conn.GetAuthInformation())
   677  	if err != nil {
   678  		return err
   679  	}
   680  	vm.OwnerUsers = ownerUsers
   681  	vm.ownerUsers = make(map[string]struct{}, len(ownerUsers))
   682  	for _, username := range ownerUsers {
   683  		vm.ownerUsers[username] = struct{}{}
   684  	}
   685  	vm.Volumes = vmInfo.Volumes
   686  	if err := <-tryAllocateMemory(vmInfo.MemoryInMiB); err != nil {
   687  		return err
   688  	}
   689  	var secondaryVolumes []proto.Volume
   690  	for index, volume := range vmInfo.Volumes {
   691  		if index > 0 {
   692  			secondaryVolumes = append(secondaryVolumes, volume)
   693  		}
   694  	}
   695  	err = vm.setupVolumes(vmInfo.Volumes[0].Size, secondaryVolumes,
   696  		vmInfo.SpreadVolumes)
   697  	if err != nil {
   698  		return err
   699  	}
   700  	defer func() { // Evaluate vm at return time, not defer time.
   701  		if vm == nil {
   702  			return
   703  		}
   704  		vm.cleanup()
   705  	}()
   706  	vm.ownerUsers = make(map[string]struct{}, len(vm.OwnerUsers))
   707  	for _, username := range vm.OwnerUsers {
   708  		vm.ownerUsers[username] = struct{}{}
   709  	}
   710  	if err := os.MkdirAll(vm.dirname, dirPerms); err != nil {
   711  		return err
   712  	}
   713  	// Begin copying over the volumes.
   714  	err = sendVmCopyMessage(conn, "initial volume(s) copy")
   715  	if err != nil {
   716  		return err
   717  	}
   718  	err = vm.migrateVmVolumes(hypervisor, request.IpAddress, accessToken)
   719  	if err != nil {
   720  		return err
   721  	}
   722  	if getInfoReply.VmInfo.State != proto.StateStopped {
   723  		err = sendVmCopyMessage(conn, "stopping VM")
   724  		if err != nil {
   725  			return err
   726  		}
   727  		err := hyperclient.StopVm(hypervisor, request.IpAddress,
   728  			request.AccessToken)
   729  		if err != nil {
   730  			return err
   731  		}
   732  		defer hyperclient.StartVm(hypervisor, request.IpAddress, accessToken)
   733  		err = sendVmCopyMessage(conn, "update volume(s)")
   734  		if err != nil {
   735  			return err
   736  		}
   737  		err = vm.migrateVmVolumes(hypervisor, request.IpAddress, accessToken)
   738  		if err != nil {
   739  			return err
   740  		}
   741  	}
   742  	err = migratevmUserData(hypervisor,
   743  		filepath.Join(vm.dirname, "user-data.raw"),
   744  		request.IpAddress, accessToken)
   745  	if err != nil {
   746  		return err
   747  	}
   748  	vm.setState(proto.StateStopped)
   749  	vm.destroyTimer = time.AfterFunc(time.Second*15, vm.autoDestroy)
   750  	response := proto.CopyVmResponse{
   751  		Final:     true,
   752  		IpAddress: vm.Address.IpAddress,
   753  	}
   754  	if err := conn.Encode(response); err != nil {
   755  		return err
   756  	}
   757  	vm = nil // Cancel cleanup.
   758  	m.Logger.Debugln(1, "CopyVm() finished")
   759  	return nil
   760  }
   761  
   762  func (m *Manager) createVm(conn *srpc.Conn) error {
   763  
   764  	sendError := func(conn *srpc.Conn, err error) error {
   765  		return conn.Encode(proto.CreateVmResponse{Error: err.Error()})
   766  	}
   767  
   768  	var ipAddressToSend net.IP
   769  	sendUpdate := func(conn *srpc.Conn, message string) error {
   770  		response := proto.CreateVmResponse{
   771  			IpAddress:       ipAddressToSend,
   772  			ProgressMessage: message,
   773  		}
   774  		if err := conn.Encode(response); err != nil {
   775  			return err
   776  		}
   777  		return conn.Flush()
   778  	}
   779  
   780  	m.Logger.Debugf(1, "CreateVm(%s) starting\n", conn.Username())
   781  	var request proto.CreateVmRequest
   782  	if err := conn.Decode(&request); err != nil {
   783  		return err
   784  	}
   785  	ownerUsers := make([]string, 1, len(request.OwnerUsers)+1)
   786  	ownerUsers[0] = conn.Username()
   787  	if ownerUsers[0] == "" {
   788  		return sendError(conn, errors.New("no authentication data"))
   789  	}
   790  	ownerUsers = append(ownerUsers, request.OwnerUsers...)
   791  	vm, err := m.allocateVm(request, conn.GetAuthInformation())
   792  	if err != nil {
   793  		if err := maybeDrainAll(conn, request); err != nil {
   794  			return err
   795  		}
   796  		return sendError(conn, err)
   797  	}
   798  	defer func() {
   799  		vm.cleanup() // Evaluate vm at return time, not defer time.
   800  	}()
   801  	memoryError := tryAllocateMemory(request.MemoryInMiB)
   802  	vm.OwnerUsers = ownerUsers
   803  	vm.ownerUsers = make(map[string]struct{}, len(ownerUsers))
   804  	for _, username := range ownerUsers {
   805  		vm.ownerUsers[username] = struct{}{}
   806  	}
   807  	if err := os.MkdirAll(vm.dirname, dirPerms); err != nil {
   808  		if err := maybeDrainAll(conn, request); err != nil {
   809  			return err
   810  		}
   811  		return sendError(conn, err)
   812  	}
   813  	if request.ImageName != "" {
   814  		if err := maybeDrainImage(conn, request.ImageDataSize); err != nil {
   815  			return err
   816  		}
   817  		if err := sendUpdate(conn, "getting image"); err != nil {
   818  			return err
   819  		}
   820  		client, img, imageName, err := m.getImage(request.ImageName,
   821  			request.ImageTimeout)
   822  		if err != nil {
   823  			return sendError(conn, err)
   824  		}
   825  		defer client.Close()
   826  		fs := img.FileSystem
   827  		vm.ImageName = imageName
   828  		size := computeSize(request.MinimumFreeBytes, request.RoundupPower,
   829  			fs.EstimateUsage(0))
   830  		err = vm.setupVolumes(size, request.SecondaryVolumes,
   831  			request.SpreadVolumes)
   832  		if err != nil {
   833  			return sendError(conn, err)
   834  		}
   835  		err = sendUpdate(conn, "unpacking image: "+imageName)
   836  		if err != nil {
   837  			return err
   838  		}
   839  		writeRawOptions := util.WriteRawOptions{
   840  			InitialImageName: imageName,
   841  			MinimumFreeBytes: request.MinimumFreeBytes,
   842  			RootLabel:        vm.rootLabel(),
   843  			RoundupPower:     request.RoundupPower,
   844  		}
   845  		err = m.writeRaw(vm.VolumeLocations[0], "", client, fs, writeRawOptions,
   846  			request.SkipBootloader)
   847  		if err != nil {
   848  			return sendError(conn, err)
   849  		}
   850  		m.Logger.Debugln(1, "finished writing volume")
   851  		if fi, err := os.Stat(vm.VolumeLocations[0].Filename); err != nil {
   852  			return sendError(conn, err)
   853  		} else {
   854  			vm.Volumes = []proto.Volume{{Size: uint64(fi.Size())}}
   855  		}
   856  	} else if request.ImageDataSize > 0 {
   857  		err := vm.copyRootVolume(request, conn, request.ImageDataSize)
   858  		if err != nil {
   859  			return err
   860  		}
   861  	} else if request.ImageURL != "" {
   862  		if err := maybeDrainImage(conn, request.ImageDataSize); err != nil {
   863  			return err
   864  		}
   865  		httpResponse, err := http.Get(request.ImageURL)
   866  		if err != nil {
   867  			return sendError(conn, err)
   868  		}
   869  		defer httpResponse.Body.Close()
   870  		if httpResponse.StatusCode != http.StatusOK {
   871  			return sendError(conn, errors.New(httpResponse.Status))
   872  		}
   873  		if httpResponse.ContentLength < 0 {
   874  			return sendError(conn,
   875  				errors.New("ContentLength from: "+request.ImageURL))
   876  		}
   877  		err = vm.copyRootVolume(request, httpResponse.Body,
   878  			uint64(httpResponse.ContentLength))
   879  		if err != nil {
   880  			return sendError(conn, err)
   881  		}
   882  	} else if request.MinimumFreeBytes > 0 { // Create empty root volume.
   883  		err = vm.copyRootVolume(request, nil, request.MinimumFreeBytes)
   884  		if err != nil {
   885  			return sendError(conn, err)
   886  		}
   887  	} else {
   888  		return sendError(conn, errors.New("no image specified"))
   889  	}
   890  	if request.UserDataSize > 0 {
   891  		filename := filepath.Join(vm.dirname, "user-data.raw")
   892  		if err := copyData(filename, conn, request.UserDataSize); err != nil {
   893  			return sendError(conn, err)
   894  		}
   895  	}
   896  	if len(request.SecondaryVolumes) > 0 {
   897  		err := sendUpdate(conn, "creating secondary volumes")
   898  		if err != nil {
   899  			return err
   900  		}
   901  		for index, volume := range request.SecondaryVolumes {
   902  			fname := vm.VolumeLocations[index+1].Filename
   903  			var dataReader io.Reader
   904  			if request.SecondaryVolumesData {
   905  				dataReader = conn
   906  			}
   907  			if err := copyData(fname, dataReader, volume.Size); err != nil {
   908  				return sendError(conn, err)
   909  			}
   910  			vm.Volumes = append(vm.Volumes, volume)
   911  		}
   912  	}
   913  	if len(memoryError) < 1 {
   914  		msg := "waiting for test memory allocation"
   915  		sendUpdate(conn, msg)
   916  		vm.logger.Debugln(0, msg)
   917  	}
   918  	if err := <-memoryError; err != nil {
   919  		return sendError(conn, err)
   920  	}
   921  	if vm.ipAddress == "" {
   922  		ipAddressToSend = net.ParseIP(vm.ipAddress)
   923  		if err := sendUpdate(conn, "starting VM"); err != nil {
   924  			return err
   925  		}
   926  	} else {
   927  		ipAddressToSend = net.ParseIP(vm.ipAddress)
   928  		if err := sendUpdate(conn, "starting VM "+vm.ipAddress); err != nil {
   929  			return err
   930  		}
   931  	}
   932  	dhcpTimedOut, err := vm.startManaging(request.DhcpTimeout,
   933  		request.EnableNetboot, false)
   934  	if err != nil {
   935  		return sendError(conn, err)
   936  	}
   937  	vm.destroyTimer = time.AfterFunc(time.Second*15, vm.autoDestroy)
   938  	response := proto.CreateVmResponse{
   939  		DhcpTimedOut: dhcpTimedOut,
   940  		Final:        true,
   941  		IpAddress:    net.ParseIP(vm.ipAddress),
   942  	}
   943  	if err := conn.Encode(response); err != nil {
   944  		return err
   945  	}
   946  	vm = nil // Cancel cleanup.
   947  	m.Logger.Debugln(1, "CreateVm() finished")
   948  	return nil
   949  }
   950  
   951  func (m *Manager) deleteVmVolume(ipAddr net.IP, authInfo *srpc.AuthInformation,
   952  	accessToken []byte, volumeIndex uint) error {
   953  	if volumeIndex < 1 {
   954  		return errors.New("cannot delete root volume")
   955  	}
   956  	vm, err := m.getVmLockAndAuth(ipAddr, true, authInfo, accessToken)
   957  	if err != nil {
   958  		return err
   959  	}
   960  	defer vm.mutex.Unlock()
   961  	if volumeIndex >= uint(len(vm.VolumeLocations)) {
   962  		return errors.New("volume index too large")
   963  	}
   964  	if vm.State != proto.StateStopped {
   965  		return errors.New("VM is not stopped")
   966  	}
   967  	if err := os.Remove(vm.VolumeLocations[volumeIndex].Filename); err != nil {
   968  		return err
   969  	}
   970  	os.Remove(vm.VolumeLocations[volumeIndex].DirectoryToCleanup)
   971  	volumeLocations := make([]proto.LocalVolume, 0, len(vm.VolumeLocations)-1)
   972  	volumes := make([]proto.Volume, 0, len(vm.VolumeLocations)-1)
   973  	for index, volume := range vm.VolumeLocations {
   974  		if uint(index) != volumeIndex {
   975  			volumeLocations = append(volumeLocations, volume)
   976  			volumes = append(volumes, vm.Volumes[index])
   977  		}
   978  	}
   979  	vm.VolumeLocations = volumeLocations
   980  	vm.Volumes = volumes
   981  	vm.writeAndSendInfo()
   982  	return nil
   983  }
   984  
   985  func (m *Manager) destroyVm(ipAddr net.IP, authInfo *srpc.AuthInformation,
   986  	accessToken []byte) error {
   987  	vm, err := m.getVmLockAndAuth(ipAddr, true, authInfo, accessToken)
   988  	if err != nil {
   989  		return err
   990  	}
   991  	defer vm.mutex.Unlock()
   992  	switch vm.State {
   993  	case proto.StateStarting:
   994  		return errors.New("VM is starting")
   995  	case proto.StateRunning:
   996  		if vm.DestroyProtection {
   997  			return errors.New("cannot destroy running VM when protected")
   998  		}
   999  		vm.setState(proto.StateDestroying)
  1000  		vm.commandChannel <- "quit"
  1001  	case proto.StateStopping:
  1002  		return errors.New("VM is stopping")
  1003  	case proto.StateStopped, proto.StateFailedToStart, proto.StateMigrating,
  1004  		proto.StateExporting:
  1005  		vm.delete()
  1006  	case proto.StateDestroying:
  1007  		return errors.New("VM is already destroying")
  1008  	default:
  1009  		return errors.New("unknown state: " + vm.State.String())
  1010  	}
  1011  	return nil
  1012  }
  1013  
  1014  func (m *Manager) discardVmAccessToken(ipAddr net.IP,
  1015  	authInfo *srpc.AuthInformation, accessToken []byte) error {
  1016  	vm, err := m.getVmLockAndAuth(ipAddr, true, authInfo, accessToken)
  1017  	if err != nil {
  1018  		return err
  1019  	}
  1020  	defer vm.mutex.Unlock()
  1021  	for index := range vm.accessToken { // Scrub token.
  1022  		vm.accessToken[index] = 0
  1023  	}
  1024  	vm.accessToken = nil
  1025  	return nil
  1026  }
  1027  
  1028  func (m *Manager) discardVmOldImage(ipAddr net.IP,
  1029  	authInfo *srpc.AuthInformation) error {
  1030  	vm, err := m.getVmLockAndAuth(ipAddr, true, authInfo, nil)
  1031  	if err != nil {
  1032  		return err
  1033  	}
  1034  	defer vm.mutex.Unlock()
  1035  	return os.Remove(vm.VolumeLocations[0].Filename + ".old")
  1036  }
  1037  
  1038  func (m *Manager) discardVmOldUserData(ipAddr net.IP,
  1039  	authInfo *srpc.AuthInformation) error {
  1040  	vm, err := m.getVmLockAndAuth(ipAddr, true, authInfo, nil)
  1041  	if err != nil {
  1042  		return err
  1043  	}
  1044  	defer vm.mutex.Unlock()
  1045  	return os.Remove(filepath.Join(vm.dirname, "user-data.old"))
  1046  }
  1047  
  1048  func (m *Manager) discardVmSnapshot(ipAddr net.IP,
  1049  	authInfo *srpc.AuthInformation) error {
  1050  	vm, err := m.getVmLockAndAuth(ipAddr, true, authInfo, nil)
  1051  	if err != nil {
  1052  		return err
  1053  	}
  1054  	defer vm.mutex.Unlock()
  1055  	return vm.discardSnapshot()
  1056  }
  1057  
  1058  func (m *Manager) exportLocalVm(authInfo *srpc.AuthInformation,
  1059  	request proto.ExportLocalVmRequest) (*proto.ExportLocalVmInfo, error) {
  1060  	if !bytes.Equal(m.rootCookie, request.VerificationCookie) {
  1061  		return nil, fmt.Errorf("bad verification cookie: you are not root")
  1062  	}
  1063  	vm, err := m.getVmLockAndAuth(request.IpAddress, true, authInfo, nil)
  1064  	if err != nil {
  1065  		return nil, err
  1066  	}
  1067  	defer vm.mutex.Unlock()
  1068  	if vm.State != proto.StateStopped {
  1069  		return nil, errors.New("VM is not stopped")
  1070  	}
  1071  	bridges, _, err := vm.getBridgesAndOptions(false)
  1072  	if err != nil {
  1073  		return nil, err
  1074  	}
  1075  	vm.setState(proto.StateExporting)
  1076  	vmInfo := proto.ExportLocalVmInfo{
  1077  		Bridges:     bridges,
  1078  		LocalVmInfo: vm.LocalVmInfo,
  1079  	}
  1080  	return &vmInfo, nil
  1081  }
  1082  
  1083  func (m *Manager) getImage(searchName string, imageTimeout time.Duration) (
  1084  	*srpc.Client, *image.Image, string, error) {
  1085  	client, err := srpc.DialHTTP("tcp", m.ImageServerAddress, 0)
  1086  	if err != nil {
  1087  		return nil, nil, "",
  1088  			fmt.Errorf("error connecting to image server: %s: %s",
  1089  				m.ImageServerAddress, err)
  1090  	}
  1091  	doClose := true
  1092  	defer func() {
  1093  		if doClose {
  1094  			client.Close()
  1095  		}
  1096  	}()
  1097  	if isDir, err := imclient.CheckDirectory(client, searchName); err != nil {
  1098  		return nil, nil, "", err
  1099  	} else if isDir {
  1100  		imageName, err := imclient.FindLatestImage(client, searchName, false)
  1101  		if err != nil {
  1102  			return nil, nil, "", err
  1103  		}
  1104  		if imageName == "" {
  1105  			return nil, nil, "",
  1106  				errors.New("no images in directory: " + searchName)
  1107  		}
  1108  		img, err := imclient.GetImage(client, imageName)
  1109  		if err != nil {
  1110  			return nil, nil, "", err
  1111  		}
  1112  		img.FileSystem.RebuildInodePointers()
  1113  		doClose = false
  1114  		return client, img, imageName, nil
  1115  	}
  1116  	img, err := imclient.GetImageWithTimeout(client, searchName, imageTimeout)
  1117  	if err != nil {
  1118  		return nil, nil, "", err
  1119  	}
  1120  	if img == nil {
  1121  		return nil, nil, "", errors.New("timeout getting image")
  1122  	}
  1123  	if err := img.FileSystem.RebuildInodePointers(); err != nil {
  1124  		return nil, nil, "", err
  1125  	}
  1126  	doClose = false
  1127  	return client, img, searchName, nil
  1128  }
  1129  
  1130  func (m *Manager) getNumVMs() (uint, uint) {
  1131  	m.mutex.RLock()
  1132  	defer m.mutex.RUnlock()
  1133  	var numRunning, numStopped uint
  1134  	for _, vm := range m.vms {
  1135  		if vm.State == proto.StateRunning {
  1136  			numRunning++
  1137  		} else {
  1138  			numStopped++
  1139  		}
  1140  	}
  1141  	return numRunning, numStopped
  1142  }
  1143  
  1144  func (m *Manager) getVmAccessToken(ipAddr net.IP,
  1145  	authInfo *srpc.AuthInformation, lifetime time.Duration) ([]byte, error) {
  1146  	if lifetime < time.Minute {
  1147  		return nil, errors.New("lifetime is less than 1 minute")
  1148  	}
  1149  	if lifetime > time.Hour*24 {
  1150  		return nil, errors.New("lifetime is greater than 1 day")
  1151  	}
  1152  	vm, err := m.getVmLockAndAuth(ipAddr, true, authInfo, nil)
  1153  	if err != nil {
  1154  		return nil, err
  1155  	}
  1156  	defer vm.mutex.Unlock()
  1157  	if vm.accessToken != nil {
  1158  		return nil, errors.New("someone else has the access token")
  1159  	}
  1160  	vm.accessToken = nil
  1161  	token := make([]byte, 32)
  1162  	if _, err := rand.Read(token); err != nil {
  1163  		return nil, err
  1164  	}
  1165  	vm.accessToken = token
  1166  	cleanupNotifier := make(chan struct{}, 1)
  1167  	vm.accessTokenCleanupNotifier = cleanupNotifier
  1168  	go func() {
  1169  		timer := time.NewTimer(lifetime)
  1170  		select {
  1171  		case <-timer.C:
  1172  		case <-cleanupNotifier:
  1173  		}
  1174  		vm.mutex.Lock()
  1175  		defer vm.mutex.Unlock()
  1176  		for index := 0; index < len(vm.accessToken); index++ {
  1177  			vm.accessToken[index] = 0 // Scrub sensitive data.
  1178  		}
  1179  		vm.accessToken = nil
  1180  	}()
  1181  	return token, nil
  1182  }
  1183  
  1184  func (m *Manager) getVmAndLock(ipAddr net.IP, write bool) (*vmInfoType, error) {
  1185  	ipStr := ipAddr.String()
  1186  	m.mutex.RLock()
  1187  	if vm := m.vms[ipStr]; vm == nil {
  1188  		m.mutex.RUnlock()
  1189  		return nil, fmt.Errorf("no VM with IP address: %s found", ipStr)
  1190  	} else {
  1191  		if write {
  1192  			vm.mutex.Lock()
  1193  		} else {
  1194  			vm.mutex.RLock()
  1195  		}
  1196  		m.mutex.RUnlock()
  1197  		return vm, nil
  1198  	}
  1199  }
  1200  
  1201  func (m *Manager) getVmLockAndAuth(ipAddr net.IP, write bool,
  1202  	authInfo *srpc.AuthInformation, accessToken []byte) (*vmInfoType, error) {
  1203  	vm, err := m.getVmAndLock(ipAddr, write)
  1204  	if err != nil {
  1205  		return nil, err
  1206  	}
  1207  	if err := vm.checkAuth(authInfo, accessToken); err != nil {
  1208  		if write {
  1209  			vm.mutex.Unlock()
  1210  		} else {
  1211  			vm.mutex.RUnlock()
  1212  		}
  1213  		return nil, err
  1214  	}
  1215  	return vm, nil
  1216  }
  1217  
  1218  func (m *Manager) getVmBootLog(ipAddr net.IP) (io.ReadCloser, error) {
  1219  	vm, err := m.getVmAndLock(ipAddr, false)
  1220  	if err != nil {
  1221  		return nil, err
  1222  	}
  1223  	filename := filepath.Join(vm.dirname, "bootlog")
  1224  	vm.mutex.RUnlock()
  1225  	return os.Open(filename)
  1226  }
  1227  
  1228  func (m *Manager) getVmInfo(ipAddr net.IP) (proto.VmInfo, error) {
  1229  	vm, err := m.getVmAndLock(ipAddr, false)
  1230  	if err != nil {
  1231  		return proto.VmInfo{}, err
  1232  	}
  1233  	defer vm.mutex.RUnlock()
  1234  	return vm.VmInfo, nil
  1235  }
  1236  
  1237  func (m *Manager) getVmUserData(ipAddr net.IP, authInfo *srpc.AuthInformation,
  1238  	accessToken []byte) (io.ReadCloser, uint64, error) {
  1239  	vm, err := m.getVmLockAndAuth(ipAddr, false, authInfo, accessToken)
  1240  	if err != nil {
  1241  		return nil, 0, err
  1242  	}
  1243  	filename := filepath.Join(vm.dirname, "user-data.raw")
  1244  	vm.mutex.RUnlock()
  1245  	if file, err := os.Open(filename); err != nil {
  1246  		return nil, 0, err
  1247  	} else if fi, err := file.Stat(); err != nil {
  1248  		return nil, 0, err
  1249  	} else {
  1250  		return file, uint64(fi.Size()), nil
  1251  	}
  1252  }
  1253  
  1254  func (m *Manager) getVmVolume(conn *srpc.Conn) error {
  1255  	var request proto.GetVmVolumeRequest
  1256  	if err := conn.Decode(&request); err != nil {
  1257  		return err
  1258  	}
  1259  	vm, err := m.getVmLockAndAuth(request.IpAddress, false,
  1260  		conn.GetAuthInformation(), request.AccessToken)
  1261  	if err != nil {
  1262  		return conn.Encode(proto.GetVmVolumeResponse{Error: err.Error()})
  1263  	}
  1264  	defer vm.mutex.RUnlock()
  1265  	if request.VolumeIndex == 0 && vm.getActiveKernelPath() != "" {
  1266  		return conn.Encode(proto.GetVmVolumeResponse{
  1267  			Error: "cannot get root volume with separate kernel"})
  1268  	}
  1269  	if request.VolumeIndex >= uint(len(vm.VolumeLocations)) {
  1270  		return conn.Encode(proto.GetVmVolumeResponse{
  1271  			Error: "index too large"})
  1272  	}
  1273  	file, err := os.Open(vm.VolumeLocations[request.VolumeIndex].Filename)
  1274  	if err != nil {
  1275  		return conn.Encode(proto.GetVmVolumeResponse{Error: err.Error()})
  1276  	}
  1277  	defer file.Close()
  1278  	if err := conn.Encode(proto.GetVmVolumeResponse{}); err != nil {
  1279  		return err
  1280  	}
  1281  	if err := conn.Flush(); err != nil {
  1282  		return err
  1283  	}
  1284  	return rsync.ServeBlocks(conn, conn, conn, file,
  1285  		vm.Volumes[request.VolumeIndex].Size)
  1286  }
  1287  
  1288  func (m *Manager) importLocalVm(authInfo *srpc.AuthInformation,
  1289  	request proto.ImportLocalVmRequest) error {
  1290  	requestedIpAddrs := make(map[string]struct{},
  1291  		1+len(request.SecondaryAddresses))
  1292  	requestedMacAddrs := make(map[string]struct{},
  1293  		1+len(request.SecondaryAddresses))
  1294  	requestedIpAddrs[request.Address.IpAddress.String()] = struct{}{}
  1295  	requestedMacAddrs[request.Address.MacAddress] = struct{}{}
  1296  	for _, addr := range request.SecondaryAddresses {
  1297  		ipAddr := addr.IpAddress.String()
  1298  		if _, ok := requestedIpAddrs[ipAddr]; ok {
  1299  			return fmt.Errorf("duplicate address: %s", ipAddr)
  1300  		}
  1301  		requestedIpAddrs[ipAddr] = struct{}{}
  1302  		if _, ok := requestedMacAddrs[addr.MacAddress]; ok {
  1303  			return fmt.Errorf("duplicate address: %s", addr.MacAddress)
  1304  		}
  1305  		requestedIpAddrs[addr.MacAddress] = struct{}{}
  1306  	}
  1307  	if !bytes.Equal(m.rootCookie, request.VerificationCookie) {
  1308  		return fmt.Errorf("bad verification cookie: you are not root")
  1309  	}
  1310  	request.VmInfo.OwnerUsers = []string{authInfo.Username}
  1311  	request.VmInfo.Uncommitted = true
  1312  	volumeDirectories := make(map[string]struct{}, len(m.volumeDirectories))
  1313  	for _, dirname := range m.volumeDirectories {
  1314  		volumeDirectories[dirname] = struct{}{}
  1315  	}
  1316  	volumes := make([]proto.Volume, 0, len(request.VolumeFilenames))
  1317  	for index, filename := range request.VolumeFilenames {
  1318  		dirname := filepath.Dir(filepath.Dir(filepath.Dir(filename)))
  1319  		if _, ok := volumeDirectories[dirname]; !ok {
  1320  			return fmt.Errorf("%s not in a volume directory", filename)
  1321  		}
  1322  		if fi, err := os.Lstat(filename); err != nil {
  1323  			return err
  1324  		} else if fi.Mode()&os.ModeType != 0 {
  1325  			return fmt.Errorf("%s is not a regular file", filename)
  1326  		} else {
  1327  			var volumeFormat proto.VolumeFormat
  1328  			if index < len(request.VmInfo.Volumes) {
  1329  				volumeFormat = request.VmInfo.Volumes[index].Format
  1330  			}
  1331  			volumes = append(volumes, proto.Volume{
  1332  				Size:   uint64(fi.Size()),
  1333  				Format: volumeFormat,
  1334  			})
  1335  		}
  1336  	}
  1337  	request.Volumes = volumes
  1338  	if err := <-tryAllocateMemory(request.MemoryInMiB); err != nil {
  1339  		return err
  1340  	}
  1341  	ipAddress := request.Address.IpAddress.String()
  1342  	vm := &vmInfoType{
  1343  		LocalVmInfo: proto.LocalVmInfo{
  1344  			VmInfo: request.VmInfo,
  1345  		},
  1346  		manager:          m,
  1347  		dirname:          filepath.Join(m.StateDir, "VMs", ipAddress),
  1348  		ipAddress:        ipAddress,
  1349  		ownerUsers:       map[string]struct{}{authInfo.Username: {}},
  1350  		logger:           prefixlogger.New(ipAddress+": ", m.Logger),
  1351  		metadataChannels: make(map[chan<- string]struct{}),
  1352  	}
  1353  	vm.VmInfo.State = proto.StateStarting
  1354  	m.mutex.Lock()
  1355  	defer m.mutex.Unlock()
  1356  	if _, ok := m.vms[ipAddress]; ok {
  1357  		return fmt.Errorf("%s already exists", ipAddress)
  1358  	}
  1359  	for _, poolAddress := range m.addressPool.Registered {
  1360  		ipAddr := poolAddress.IpAddress.String()
  1361  		if _, ok := requestedIpAddrs[ipAddr]; ok {
  1362  			return fmt.Errorf("%s is in address pool", ipAddr)
  1363  		}
  1364  		if _, ok := requestedMacAddrs[poolAddress.MacAddress]; ok {
  1365  			return fmt.Errorf("%s is in address pool", poolAddress.MacAddress)
  1366  		}
  1367  	}
  1368  	subnetId := m.getMatchingSubnet(request.Address.IpAddress)
  1369  	if subnetId == "" {
  1370  		return fmt.Errorf("no matching subnet for: %s\n", ipAddress)
  1371  	}
  1372  	vm.VmInfo.SubnetId = subnetId
  1373  	vm.VmInfo.SecondarySubnetIDs = nil
  1374  	for _, addr := range request.SecondaryAddresses {
  1375  		subnetId := m.getMatchingSubnet(addr.IpAddress)
  1376  		if subnetId == "" {
  1377  			return fmt.Errorf("no matching subnet for: %s\n", addr.IpAddress)
  1378  		}
  1379  		vm.VmInfo.SecondarySubnetIDs = append(vm.VmInfo.SecondarySubnetIDs,
  1380  			subnetId)
  1381  	}
  1382  	defer func() {
  1383  		if vm == nil {
  1384  			return
  1385  		}
  1386  		delete(m.vms, vm.ipAddress)
  1387  		m.sendVmInfo(vm.ipAddress, nil)
  1388  		os.RemoveAll(vm.dirname)
  1389  		for _, volume := range vm.VolumeLocations {
  1390  			os.RemoveAll(volume.DirectoryToCleanup)
  1391  		}
  1392  	}()
  1393  	if err := os.MkdirAll(vm.dirname, dirPerms); err != nil {
  1394  		return err
  1395  	}
  1396  	for index, sourceFilename := range request.VolumeFilenames {
  1397  		dirname := filepath.Join(filepath.Dir(filepath.Dir(
  1398  			filepath.Dir(sourceFilename))),
  1399  			ipAddress)
  1400  		if err := os.MkdirAll(dirname, dirPerms); err != nil {
  1401  			return err
  1402  		}
  1403  		var destFilename string
  1404  		if index == 0 {
  1405  			destFilename = filepath.Join(dirname, "root")
  1406  		} else {
  1407  			destFilename = filepath.Join(dirname,
  1408  				fmt.Sprintf("secondary-volume.%d", index-1))
  1409  		}
  1410  		if err := os.Link(sourceFilename, destFilename); err != nil {
  1411  			return err
  1412  		}
  1413  		vm.VolumeLocations = append(vm.VolumeLocations, proto.LocalVolume{
  1414  			dirname, destFilename})
  1415  	}
  1416  	m.vms[ipAddress] = vm
  1417  	if _, err := vm.startManaging(0, false, true); err != nil {
  1418  		return err
  1419  	}
  1420  	vm = nil // Cancel cleanup.
  1421  	return nil
  1422  }
  1423  
  1424  func (m *Manager) listVMs(request proto.ListVMsRequest) []string {
  1425  	m.mutex.RLock()
  1426  	ipAddrs := make([]string, 0, len(m.vms))
  1427  	for ipAddr, vm := range m.vms {
  1428  		if request.IgnoreStateMask&(1<<vm.State) != 0 {
  1429  			continue
  1430  		}
  1431  		include := true
  1432  		if len(request.OwnerUsers) > 0 {
  1433  			include = false
  1434  			for _, ownerUser := range request.OwnerUsers {
  1435  				if _, ok := vm.ownerUsers[ownerUser]; ok {
  1436  					include = true
  1437  					break
  1438  				}
  1439  			}
  1440  		}
  1441  		if include {
  1442  			ipAddrs = append(ipAddrs, ipAddr)
  1443  		}
  1444  	}
  1445  	m.mutex.RUnlock()
  1446  	if request.Sort {
  1447  		verstr.Sort(ipAddrs)
  1448  	}
  1449  	return ipAddrs
  1450  }
  1451  
  1452  func (m *Manager) migrateVm(conn *srpc.Conn) error {
  1453  	var request proto.MigrateVmRequest
  1454  	if err := conn.Decode(&request); err != nil {
  1455  		return err
  1456  	}
  1457  	hypervisor, err := srpc.DialHTTP("tcp", request.SourceHypervisor, 0)
  1458  	if err != nil {
  1459  		return err
  1460  	}
  1461  	defer hypervisor.Close()
  1462  	defer func() {
  1463  		req := proto.DiscardVmAccessTokenRequest{
  1464  			AccessToken: request.AccessToken,
  1465  			IpAddress:   request.IpAddress}
  1466  		var reply proto.DiscardVmAccessTokenResponse
  1467  		hypervisor.RequestReply("Hypervisor.DiscardVmAccessToken",
  1468  			req, &reply)
  1469  	}()
  1470  	ipAddress := request.IpAddress.String()
  1471  	m.mutex.RLock()
  1472  	_, ok := m.vms[ipAddress]
  1473  	subnetId := m.getMatchingSubnet(request.IpAddress)
  1474  	m.mutex.RUnlock()
  1475  	if ok {
  1476  		return errors.New("cannot migrate to the same hypervisor")
  1477  	}
  1478  	if subnetId == "" {
  1479  		return fmt.Errorf("no matching subnet for: %s\n", request.IpAddress)
  1480  	}
  1481  	getInfoRequest := proto.GetVmInfoRequest{request.IpAddress}
  1482  	var getInfoReply proto.GetVmInfoResponse
  1483  	err = hypervisor.RequestReply("Hypervisor.GetVmInfo", getInfoRequest,
  1484  		&getInfoReply)
  1485  	if err != nil {
  1486  		return err
  1487  	}
  1488  	accessToken := request.AccessToken
  1489  	vmInfo := getInfoReply.VmInfo
  1490  	if subnetId != vmInfo.SubnetId {
  1491  		return fmt.Errorf("subnet ID changing from: %s to: %s",
  1492  			vmInfo.SubnetId, subnetId)
  1493  	}
  1494  	if !request.IpAddress.Equal(vmInfo.Address.IpAddress) {
  1495  		return fmt.Errorf("inconsistent IP address: %s",
  1496  			vmInfo.Address.IpAddress)
  1497  	}
  1498  	if err := m.migrateVmChecks(vmInfo); err != nil {
  1499  		return err
  1500  	}
  1501  	volumeDirectories, err := m.getVolumeDirectories(vmInfo.Volumes[0].Size,
  1502  		vmInfo.Volumes[1:], vmInfo.SpreadVolumes)
  1503  	if err != nil {
  1504  		return err
  1505  	}
  1506  	vm := &vmInfoType{
  1507  		LocalVmInfo: proto.LocalVmInfo{
  1508  			VmInfo: vmInfo,
  1509  			VolumeLocations: make([]proto.LocalVolume, 0,
  1510  				len(volumeDirectories)),
  1511  		},
  1512  		manager:          m,
  1513  		dirname:          filepath.Join(m.StateDir, "VMs", ipAddress),
  1514  		doNotWriteOrSend: true,
  1515  		ipAddress:        ipAddress,
  1516  		logger:           prefixlogger.New(ipAddress+": ", m.Logger),
  1517  		metadataChannels: make(map[chan<- string]struct{}),
  1518  	}
  1519  	vm.Uncommitted = true
  1520  	defer func() { // Evaluate vm at return time, not defer time.
  1521  		if vm == nil {
  1522  			return
  1523  		}
  1524  		vm.cleanup()
  1525  		hyperclient.PrepareVmForMigration(hypervisor, request.IpAddress,
  1526  			accessToken, false)
  1527  		if vmInfo.State == proto.StateRunning {
  1528  			hyperclient.StartVm(hypervisor, request.IpAddress, accessToken)
  1529  		}
  1530  	}()
  1531  	vm.ownerUsers = make(map[string]struct{}, len(vm.OwnerUsers))
  1532  	for _, username := range vm.OwnerUsers {
  1533  		vm.ownerUsers[username] = struct{}{}
  1534  	}
  1535  	if err := os.MkdirAll(vm.dirname, dirPerms); err != nil {
  1536  		return err
  1537  	}
  1538  	for index, _dirname := range volumeDirectories {
  1539  		dirname := filepath.Join(_dirname, ipAddress)
  1540  		if err := os.MkdirAll(dirname, dirPerms); err != nil {
  1541  			return err
  1542  		}
  1543  		var filename string
  1544  		if index == 0 {
  1545  			filename = filepath.Join(dirname, "root")
  1546  		} else {
  1547  			filename = filepath.Join(dirname,
  1548  				fmt.Sprintf("secondary-volume.%d", index-1))
  1549  		}
  1550  		vm.VolumeLocations = append(vm.VolumeLocations, proto.LocalVolume{
  1551  			DirectoryToCleanup: dirname,
  1552  			Filename:           filename,
  1553  		})
  1554  	}
  1555  	if vmInfo.State == proto.StateStopped {
  1556  		err := hyperclient.PrepareVmForMigration(hypervisor, request.IpAddress,
  1557  			request.AccessToken, true)
  1558  		if err != nil {
  1559  			return err
  1560  		}
  1561  	}
  1562  	// Begin copying over the volumes.
  1563  	err = sendVmMigrationMessage(conn, "initial volume(s) copy")
  1564  	if err != nil {
  1565  		return err
  1566  	}
  1567  	err = vm.migrateVmVolumes(hypervisor, vm.Address.IpAddress, accessToken)
  1568  	if err != nil {
  1569  		return err
  1570  	}
  1571  	if vmInfo.State != proto.StateStopped {
  1572  		err = sendVmMigrationMessage(conn, "stopping VM")
  1573  		if err != nil {
  1574  			return err
  1575  		}
  1576  		err := hyperclient.StopVm(hypervisor, request.IpAddress,
  1577  			request.AccessToken)
  1578  		if err != nil {
  1579  			return err
  1580  		}
  1581  		err = hyperclient.PrepareVmForMigration(hypervisor, request.IpAddress,
  1582  			request.AccessToken, true)
  1583  		if err != nil {
  1584  			return err
  1585  		}
  1586  		err = sendVmMigrationMessage(conn, "update volume(s)")
  1587  		if err != nil {
  1588  			return err
  1589  		}
  1590  		err = vm.migrateVmVolumes(hypervisor, vm.Address.IpAddress, accessToken)
  1591  		if err != nil {
  1592  			return err
  1593  		}
  1594  	}
  1595  	err = migratevmUserData(hypervisor,
  1596  		filepath.Join(vm.dirname, "user-data.raw"),
  1597  		request.IpAddress, accessToken)
  1598  	if err != nil {
  1599  		return err
  1600  	}
  1601  	if err := sendVmMigrationMessage(conn, "starting VM"); err != nil {
  1602  		return err
  1603  	}
  1604  	vm.State = proto.StateStarting
  1605  	m.mutex.Lock()
  1606  	m.vms[ipAddress] = vm
  1607  	m.mutex.Unlock()
  1608  	dhcpTimedOut, err := vm.startManaging(request.DhcpTimeout, false, false)
  1609  	if err != nil {
  1610  		return err
  1611  	}
  1612  	if dhcpTimedOut {
  1613  		return fmt.Errorf("DHCP timed out")
  1614  	}
  1615  	err = conn.Encode(proto.MigrateVmResponse{RequestCommit: true})
  1616  	if err != nil {
  1617  		return err
  1618  	}
  1619  	if err := conn.Flush(); err != nil {
  1620  		return err
  1621  	}
  1622  	var reply proto.MigrateVmResponseResponse
  1623  	if err := conn.Decode(&reply); err != nil {
  1624  		return err
  1625  	}
  1626  	if !reply.Commit {
  1627  		return fmt.Errorf("VM migration abandoned")
  1628  	}
  1629  	if err := m.registerAddress(vm.Address); err != nil {
  1630  		return err
  1631  	}
  1632  	for _, address := range vm.SecondaryAddresses {
  1633  		if err := m.registerAddress(address); err != nil {
  1634  			return err
  1635  		}
  1636  	}
  1637  	vm.doNotWriteOrSend = false
  1638  	vm.Uncommitted = false
  1639  	vm.writeAndSendInfo()
  1640  	err = hyperclient.DestroyVm(hypervisor, request.IpAddress, accessToken)
  1641  	if err != nil {
  1642  		m.Logger.Printf("error cleaning up old migrated VM: %s\n", ipAddress)
  1643  	}
  1644  	vm = nil // Cancel cleanup.
  1645  	return nil
  1646  }
  1647  
  1648  func sendVmCopyMessage(conn *srpc.Conn, message string) error {
  1649  	request := proto.CopyVmResponse{ProgressMessage: message}
  1650  	if err := conn.Encode(request); err != nil {
  1651  		return err
  1652  	}
  1653  	return conn.Flush()
  1654  }
  1655  
  1656  func sendVmMigrationMessage(conn *srpc.Conn, message string) error {
  1657  	request := proto.MigrateVmResponse{ProgressMessage: message}
  1658  	if err := conn.Encode(request); err != nil {
  1659  		return err
  1660  	}
  1661  	return conn.Flush()
  1662  }
  1663  
  1664  func sendVmPatchImageMessage(conn *srpc.Conn, message string) error {
  1665  	request := proto.PatchVmImageResponse{ProgressMessage: message}
  1666  	if err := conn.Encode(request); err != nil {
  1667  		return err
  1668  	}
  1669  	return conn.Flush()
  1670  }
  1671  
  1672  func (m *Manager) migrateVmChecks(vmInfo proto.VmInfo) error {
  1673  	switch vmInfo.State {
  1674  	case proto.StateStopped:
  1675  	case proto.StateRunning:
  1676  	default:
  1677  		return fmt.Errorf("VM state: %s is not stopped/running", vmInfo.State)
  1678  	}
  1679  	m.mutex.RLock()
  1680  	defer m.mutex.RUnlock()
  1681  	for index, address := range vmInfo.SecondaryAddresses {
  1682  		subnetId := m.getMatchingSubnet(address.IpAddress)
  1683  		if subnetId == "" {
  1684  			return fmt.Errorf("no matching subnet for: %s\n", address.IpAddress)
  1685  		}
  1686  		if subnetId != vmInfo.SecondarySubnetIDs[index] {
  1687  			return fmt.Errorf("subnet ID changing from: %s to: %s",
  1688  				vmInfo.SecondarySubnetIDs[index], subnetId)
  1689  		}
  1690  	}
  1691  	if err := m.checkSufficientCPUWithLock(vmInfo.MilliCPUs); err != nil {
  1692  		return err
  1693  	}
  1694  	if err := m.checkSufficientMemoryWithLock(vmInfo.MemoryInMiB); err != nil {
  1695  		return err
  1696  	}
  1697  	if err := <-tryAllocateMemory(vmInfo.MemoryInMiB); err != nil {
  1698  		return err
  1699  	}
  1700  	return nil
  1701  }
  1702  
  1703  func migratevmUserData(hypervisor *srpc.Client, filename string,
  1704  	ipAddr net.IP, accessToken []byte) error {
  1705  	conn, err := hypervisor.Call("Hypervisor.GetVmUserData")
  1706  	if err != nil {
  1707  		return err
  1708  	}
  1709  	defer conn.Close()
  1710  	request := proto.GetVmUserDataRequest{
  1711  		AccessToken: accessToken,
  1712  		IpAddress:   ipAddr,
  1713  	}
  1714  	if err := conn.Encode(request); err != nil {
  1715  		return fmt.Errorf("error encoding request: %s", err)
  1716  	}
  1717  	if err := conn.Flush(); err != nil {
  1718  		return err
  1719  	}
  1720  	var reply proto.GetVmUserDataResponse
  1721  	if err := conn.Decode(&reply); err != nil {
  1722  		return err
  1723  	}
  1724  	if err := errors.New(reply.Error); err != nil {
  1725  		return err
  1726  	}
  1727  	if reply.Length < 1 {
  1728  		return nil
  1729  	}
  1730  	writer, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_EXCL,
  1731  		privateFilePerms)
  1732  	if err != nil {
  1733  		io.CopyN(ioutil.Discard, conn, int64(reply.Length))
  1734  		return err
  1735  	}
  1736  	defer writer.Close()
  1737  	if _, err := io.CopyN(writer, conn, int64(reply.Length)); err != nil {
  1738  		return err
  1739  	}
  1740  	return nil
  1741  }
  1742  
  1743  func (vm *vmInfoType) migrateVmVolumes(hypervisor *srpc.Client,
  1744  	sourceIpAddr net.IP, accessToken []byte) error {
  1745  	for index, volume := range vm.VolumeLocations {
  1746  		_, err := migrateVmVolume(hypervisor, volume.Filename, uint(index),
  1747  			vm.Volumes[index].Size, sourceIpAddr, accessToken)
  1748  		if err != nil {
  1749  			return err
  1750  		}
  1751  	}
  1752  	return nil
  1753  }
  1754  
  1755  func migrateVmVolume(hypervisor *srpc.Client, filename string,
  1756  	volumeIndex uint, size uint64, ipAddr net.IP, accessToken []byte) (
  1757  	*rsync.Stats, error) {
  1758  	var initialFileSize uint64
  1759  	reader, err := os.OpenFile(filename, os.O_RDONLY, 0)
  1760  	if err != nil {
  1761  		if !os.IsNotExist(err) {
  1762  			return nil, err
  1763  		}
  1764  	} else {
  1765  		defer reader.Close()
  1766  		if fi, err := reader.Stat(); err != nil {
  1767  			return nil, err
  1768  		} else {
  1769  			initialFileSize = uint64(fi.Size())
  1770  			if initialFileSize > size {
  1771  				return nil, errors.New("file larger than volume")
  1772  			}
  1773  		}
  1774  	}
  1775  	writer, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE,
  1776  		privateFilePerms)
  1777  	if err != nil {
  1778  		return nil, err
  1779  	}
  1780  	defer writer.Close()
  1781  	request := proto.GetVmVolumeRequest{
  1782  		AccessToken: accessToken,
  1783  		IpAddress:   ipAddr,
  1784  		VolumeIndex: volumeIndex,
  1785  	}
  1786  	conn, err := hypervisor.Call("Hypervisor.GetVmVolume")
  1787  	if err != nil {
  1788  		if reader == nil {
  1789  			os.Remove(filename)
  1790  		}
  1791  		return nil, err
  1792  	}
  1793  	defer conn.Close()
  1794  	if err := conn.Encode(request); err != nil {
  1795  		return nil, fmt.Errorf("error encoding request: %s", err)
  1796  	}
  1797  	if err := conn.Flush(); err != nil {
  1798  		return nil, err
  1799  	}
  1800  	var response proto.GetVmVolumeResponse
  1801  	if err := conn.Decode(&response); err != nil {
  1802  		return nil, err
  1803  	}
  1804  	if err := errors.New(response.Error); err != nil {
  1805  		return nil, err
  1806  	}
  1807  	stats, err := rsync.GetBlocks(conn, conn, conn, reader, writer, size,
  1808  		initialFileSize)
  1809  	return &stats, err
  1810  }
  1811  
  1812  func (m *Manager) notifyVmMetadataRequest(ipAddr net.IP, path string) {
  1813  	addr := ipAddr.String()
  1814  	m.mutex.RLock()
  1815  	vm, ok := m.vms[addr]
  1816  	m.mutex.RUnlock()
  1817  	if !ok {
  1818  		return
  1819  	}
  1820  	vm.mutex.Lock()
  1821  	defer vm.mutex.Unlock()
  1822  	for ch := range vm.metadataChannels {
  1823  		select {
  1824  		case ch <- path:
  1825  		default:
  1826  		}
  1827  	}
  1828  }
  1829  
  1830  func (m *Manager) patchVmImage(conn *srpc.Conn,
  1831  	request proto.PatchVmImageRequest) error {
  1832  	client, img, imageName, err := m.getImage(request.ImageName,
  1833  		request.ImageTimeout)
  1834  	if err != nil {
  1835  		return nil
  1836  	}
  1837  	if img.Filter == nil {
  1838  		return fmt.Errorf("%s contains no filter", imageName)
  1839  	}
  1840  	img.FileSystem.InodeToFilenamesTable()
  1841  	img.FileSystem.FilenameToInodeTable()
  1842  	hashToInodesTable := img.FileSystem.HashToInodesTable()
  1843  	img.FileSystem.BuildEntryMap()
  1844  	var objectsGetter objectserver.ObjectsGetter
  1845  	vm, err := m.getVmLockAndAuth(request.IpAddress, true,
  1846  		conn.GetAuthInformation(), nil)
  1847  	if err != nil {
  1848  		return err
  1849  	}
  1850  	restart := vm.State == proto.StateRunning
  1851  	defer func() {
  1852  		vm.updating = false
  1853  		vm.mutex.Unlock()
  1854  	}()
  1855  	if m.objectCache == nil {
  1856  		objectClient := objclient.AttachObjectClient(client)
  1857  		defer objectClient.Close()
  1858  		objectsGetter = objectClient
  1859  	} else if restart {
  1860  		hashes := make([]hash.Hash, 0, len(hashToInodesTable))
  1861  		for hashVal := range hashToInodesTable {
  1862  			hashes = append(hashes, hashVal)
  1863  		}
  1864  		if err := sendVmPatchImageMessage(conn, "prefetching"); err != nil {
  1865  			return err
  1866  		}
  1867  		if err := m.objectCache.FetchObjects(hashes); err != nil {
  1868  			return err
  1869  		}
  1870  		objectsGetter = m.objectCache
  1871  	} else {
  1872  		objectsGetter = m.objectCache
  1873  	}
  1874  	switch vm.State {
  1875  	case proto.StateStopped:
  1876  	case proto.StateRunning:
  1877  		if len(vm.Address.IpAddress) < 1 {
  1878  			return errors.New("cannot stop VM with externally managed lease")
  1879  		}
  1880  	default:
  1881  		return errors.New("VM is not running or stopped")
  1882  	}
  1883  	if vm.updating {
  1884  		return errors.New("cannot update already updating VM")
  1885  	}
  1886  	vm.updating = true
  1887  	bootInfo, err := util.GetBootInfo(img.FileSystem, vm.rootLabel(),
  1888  		"net.ifnames=0")
  1889  	if err != nil {
  1890  		return err
  1891  	}
  1892  	if vm.State == proto.StateRunning {
  1893  		if err := sendVmPatchImageMessage(conn, "stopping VM"); err != nil {
  1894  			return err
  1895  		}
  1896  		stoppedNotifier := make(chan struct{}, 1)
  1897  		vm.stoppedNotifier = stoppedNotifier
  1898  		vm.setState(proto.StateStopping)
  1899  		vm.commandChannel <- "system_powerdown"
  1900  		time.AfterFunc(time.Second*15, vm.kill)
  1901  		vm.mutex.Unlock()
  1902  		<-stoppedNotifier
  1903  		vm.mutex.Lock()
  1904  		if vm.State != proto.StateStopped {
  1905  			restart = false
  1906  			return errors.New("VM is not stopped after stop attempt")
  1907  		}
  1908  	}
  1909  	rootFilename := vm.VolumeLocations[0].Filename
  1910  	tmpRootFilename := rootFilename + ".new"
  1911  	if err := sendVmPatchImageMessage(conn, "copying root"); err != nil {
  1912  		return err
  1913  	}
  1914  	err = fsutil.CopyFile(tmpRootFilename, rootFilename,
  1915  		fsutil.PrivateFilePerms)
  1916  	if err != nil {
  1917  		return err
  1918  	}
  1919  	defer os.Remove(tmpRootFilename)
  1920  	rootDir, err := ioutil.TempDir(vm.dirname, "root")
  1921  	if err != nil {
  1922  		return err
  1923  	}
  1924  	defer os.Remove(rootDir)
  1925  	loopDevice, err := fsutil.LoopbackSetup(tmpRootFilename)
  1926  	if err != nil {
  1927  		return err
  1928  	}
  1929  	defer fsutil.LoopbackDelete(loopDevice)
  1930  	vm.logger.Debugf(0, "mounting: %s onto: %s\n", loopDevice, rootDir)
  1931  	err = wsyscall.Mount(loopDevice+"p1", rootDir, "ext4", 0, "")
  1932  	if err != nil {
  1933  		return err
  1934  	}
  1935  	defer syscall.Unmount(rootDir, 0)
  1936  	if err := sendVmPatchImageMessage(conn, "scanning root"); err != nil {
  1937  		return err
  1938  	}
  1939  	fs, err := scanner.ScanFileSystem(rootDir, nil, img.Filter, nil, nil, nil)
  1940  	if err != nil {
  1941  		return err
  1942  	}
  1943  	if err := fs.FileSystem.RebuildInodePointers(); err != nil {
  1944  		return err
  1945  	}
  1946  	fs.FileSystem.BuildEntryMap()
  1947  	initrdFilename := vm.getInitrdPath()
  1948  	tmpInitrdFilename := initrdFilename + ".new"
  1949  	defer os.Remove(tmpInitrdFilename)
  1950  	kernelFilename := vm.getKernelPath()
  1951  	tmpKernelFilename := kernelFilename + ".new"
  1952  	defer os.Remove(tmpKernelFilename)
  1953  	writeBootloaderConfig := false
  1954  	if _, err := os.Stat(vm.getKernelPath()); err == nil { // No bootloader.
  1955  		err := extractKernel(vm.VolumeLocations[0], ".new", objectsGetter,
  1956  			img.FileSystem, bootInfo)
  1957  		if err != nil {
  1958  			return err
  1959  		}
  1960  	} else { // Requires a bootloader.
  1961  		writeBootloaderConfig = true
  1962  	}
  1963  	subObj := domlib.Sub{FileSystem: &fs.FileSystem}
  1964  	fetchMap, _ := domlib.BuildMissingLists(subObj, img, false, true,
  1965  		vm.logger)
  1966  	objectsToFetch := objectcache.ObjectMapToCache(fetchMap)
  1967  	objectsDir := filepath.Join(rootDir, ".subd", "objects")
  1968  	defer os.RemoveAll(objectsDir)
  1969  	startTime := time.Now()
  1970  	objectsReader, err := objectsGetter.GetObjects(objectsToFetch)
  1971  	if err != nil {
  1972  		return err
  1973  	}
  1974  	defer objectsReader.Close()
  1975  	err = sendVmPatchImageMessage(conn, "pre-deleting unneeded files")
  1976  	if err != nil {
  1977  		return err
  1978  	}
  1979  	err = deleteFilesNotInImage(img.FileSystem, &fs.FileSystem, rootDir,
  1980  		vm.logger)
  1981  	if err != nil {
  1982  		return err
  1983  	}
  1984  	msg := fmt.Sprintf("fetching(%s) %d objects",
  1985  		imageName, len(objectsToFetch))
  1986  	if err := sendVmPatchImageMessage(conn, msg); err != nil {
  1987  		return err
  1988  	}
  1989  	vm.logger.Debugln(0, msg)
  1990  	for _, hashVal := range objectsToFetch {
  1991  		length, reader, err := objectsReader.NextObject()
  1992  		if err != nil {
  1993  			vm.logger.Println(err)
  1994  			return err
  1995  		}
  1996  		err = readOne(objectsDir, hashVal, length, reader)
  1997  		reader.Close()
  1998  		if err != nil {
  1999  			vm.logger.Println(err)
  2000  			return err
  2001  		}
  2002  	}
  2003  	msg = fmt.Sprintf("fetched(%s) %d objects in %s",
  2004  		imageName, len(objectsToFetch), format.Duration(time.Since(startTime)))
  2005  	if err := sendVmPatchImageMessage(conn, msg); err != nil {
  2006  		return err
  2007  	}
  2008  	vm.logger.Debugln(0, msg)
  2009  	subObj.ObjectCache = append(subObj.ObjectCache, objectsToFetch...)
  2010  	var subRequest subproto.UpdateRequest
  2011  	if domlib.BuildUpdateRequest(subObj, img, &subRequest, false, true,
  2012  		vm.logger) {
  2013  		return errors.New("failed building update: missing computed files")
  2014  	}
  2015  	subRequest.ImageName = imageName
  2016  	subRequest.Triggers = nil
  2017  	if err := sendVmPatchImageMessage(conn, "starting update"); err != nil {
  2018  		return err
  2019  	}
  2020  	vm.logger.Debugf(0, "update(%s) starting\n", imageName)
  2021  	startTime = time.Now()
  2022  	_, _, err = sublib.Update(subRequest, rootDir, objectsDir, nil, nil, nil,
  2023  		vm.logger)
  2024  	if err != nil {
  2025  		return err
  2026  	}
  2027  	if writeBootloaderConfig {
  2028  		err := bootInfo.WriteBootloaderConfig(rootDir, vm.logger)
  2029  		if err != nil {
  2030  			return err
  2031  		}
  2032  	}
  2033  	oldRootFilename := rootFilename + ".old"
  2034  	if err := os.Rename(rootFilename, oldRootFilename); err != nil {
  2035  		return err
  2036  	}
  2037  	if err := os.Rename(tmpRootFilename, rootFilename); err != nil {
  2038  		os.Rename(oldRootFilename, rootFilename)
  2039  		return err
  2040  	}
  2041  	os.Rename(initrdFilename, initrdFilename+".old")
  2042  	os.Rename(tmpInitrdFilename, initrdFilename)
  2043  	os.Rename(kernelFilename, kernelFilename+".old")
  2044  	os.Rename(tmpKernelFilename, kernelFilename)
  2045  	vm.ImageName = imageName
  2046  	vm.writeAndSendInfo()
  2047  	if restart && vm.State == proto.StateStopped {
  2048  		vm.setState(proto.StateStarting)
  2049  		sendVmPatchImageMessage(conn, "starting VM")
  2050  		vm.mutex.Unlock()
  2051  		_, err := vm.startManaging(-1, false, false)
  2052  		vm.mutex.Lock()
  2053  		if err != nil {
  2054  			return err
  2055  		}
  2056  	}
  2057  	return nil
  2058  }
  2059  
  2060  func (m *Manager) prepareVmForMigration(ipAddr net.IP,
  2061  	authInfoP *srpc.AuthInformation, accessToken []byte, enable bool) error {
  2062  	authInfo := *authInfoP
  2063  	authInfo.HaveMethodAccess = false // Require VM ownership or token.
  2064  	vm, err := m.getVmLockAndAuth(ipAddr, true, &authInfo, accessToken)
  2065  	if err != nil {
  2066  		return nil
  2067  	}
  2068  	defer vm.mutex.Unlock()
  2069  	if enable {
  2070  		if vm.Uncommitted {
  2071  			return errors.New("VM is uncommitted")
  2072  		}
  2073  		if vm.State != proto.StateStopped {
  2074  			return errors.New("VM is not stopped")
  2075  		}
  2076  		// Block reallocation of addresses until VM is destroyed, then release
  2077  		// claims on addresses.
  2078  		vm.Uncommitted = true
  2079  		vm.setState(proto.StateMigrating)
  2080  		if err := m.unregisterAddress(vm.Address, true); err != nil {
  2081  			vm.Uncommitted = false
  2082  			vm.setState(proto.StateStopped)
  2083  			return err
  2084  		}
  2085  		for _, address := range vm.SecondaryAddresses {
  2086  			if err := m.unregisterAddress(address, true); err != nil {
  2087  				vm.logger.Printf("error unregistering address: %s\n",
  2088  					address.IpAddress)
  2089  				vm.Uncommitted = false
  2090  				vm.setState(proto.StateStopped)
  2091  				return err
  2092  			}
  2093  		}
  2094  	} else {
  2095  		if vm.State != proto.StateMigrating {
  2096  			return errors.New("VM is not migrating")
  2097  		}
  2098  		// Reclaim addresses and then allow reallocation if VM is later
  2099  		// destroyed.
  2100  		if err := m.registerAddress(vm.Address); err != nil {
  2101  			vm.setState(proto.StateStopped)
  2102  			return err
  2103  		}
  2104  		for _, address := range vm.SecondaryAddresses {
  2105  			if err := m.registerAddress(address); err != nil {
  2106  				vm.logger.Printf("error registering address: %s\n",
  2107  					address.IpAddress)
  2108  				vm.setState(proto.StateStopped)
  2109  				return err
  2110  			}
  2111  		}
  2112  		vm.Uncommitted = false
  2113  		vm.setState(proto.StateStopped)
  2114  	}
  2115  	return nil
  2116  }
  2117  
  2118  func (m *Manager) registerVmMetadataNotifier(ipAddr net.IP,
  2119  	authInfo *srpc.AuthInformation, pathChannel chan<- string) error {
  2120  	vm, err := m.getVmLockAndAuth(ipAddr, true, authInfo, nil)
  2121  	if err != nil {
  2122  		return err
  2123  	}
  2124  	defer vm.mutex.Unlock()
  2125  	vm.metadataChannels[pathChannel] = struct{}{}
  2126  	return nil
  2127  }
  2128  
  2129  func (m *Manager) replaceVmImage(conn *srpc.Conn,
  2130  	authInfo *srpc.AuthInformation) error {
  2131  
  2132  	sendError := func(conn *srpc.Conn, err error) error {
  2133  		return conn.Encode(proto.ReplaceVmImageResponse{Error: err.Error()})
  2134  	}
  2135  
  2136  	sendUpdate := func(conn *srpc.Conn, message string) error {
  2137  		response := proto.ReplaceVmImageResponse{ProgressMessage: message}
  2138  		if err := conn.Encode(response); err != nil {
  2139  			return err
  2140  		}
  2141  		return conn.Flush()
  2142  	}
  2143  
  2144  	var request proto.ReplaceVmImageRequest
  2145  	if err := conn.Decode(&request); err != nil {
  2146  		return err
  2147  	}
  2148  	vm, err := m.getVmLockAndAuth(request.IpAddress, true, authInfo, nil)
  2149  	if err != nil {
  2150  		if err := maybeDrainImage(conn, request.ImageDataSize); err != nil {
  2151  			return err
  2152  		}
  2153  		return sendError(conn, err)
  2154  	}
  2155  	restart := vm.State == proto.StateRunning
  2156  	defer func() {
  2157  		vm.updating = false
  2158  		vm.mutex.Unlock()
  2159  	}()
  2160  	switch vm.State {
  2161  	case proto.StateStopped:
  2162  	case proto.StateRunning:
  2163  		if len(vm.Address.IpAddress) < 1 {
  2164  			if err := maybeDrainImage(conn, request.ImageDataSize); err != nil {
  2165  				return err
  2166  			}
  2167  			return errors.New("cannot stop VM with externally managed lease")
  2168  		}
  2169  	default:
  2170  		if err := maybeDrainImage(conn, request.ImageDataSize); err != nil {
  2171  			return err
  2172  		}
  2173  		return sendError(conn, errors.New("VM is not running or stopped"))
  2174  	}
  2175  	if vm.updating {
  2176  		return errors.New("cannot update already updating VM")
  2177  	}
  2178  	vm.updating = true
  2179  	initrdFilename := vm.getInitrdPath()
  2180  	tmpInitrdFilename := initrdFilename + ".new"
  2181  	defer os.Remove(tmpInitrdFilename)
  2182  	kernelFilename := vm.getKernelPath()
  2183  	tmpKernelFilename := kernelFilename + ".new"
  2184  	defer os.Remove(tmpKernelFilename)
  2185  	tmpRootFilename := vm.VolumeLocations[0].Filename + ".new"
  2186  	defer os.Remove(tmpRootFilename)
  2187  	var newSize uint64
  2188  	if request.ImageName != "" {
  2189  		if err := maybeDrainImage(conn, request.ImageDataSize); err != nil {
  2190  			return err
  2191  		}
  2192  		if err := sendUpdate(conn, "getting image"); err != nil {
  2193  			return err
  2194  		}
  2195  		client, img, imageName, err := m.getImage(request.ImageName,
  2196  			request.ImageTimeout)
  2197  		if err != nil {
  2198  			return sendError(conn, err)
  2199  		}
  2200  		defer client.Close()
  2201  		request.ImageName = imageName
  2202  		err = sendUpdate(conn, "unpacking image: "+imageName)
  2203  		if err != nil {
  2204  			return err
  2205  		}
  2206  		writeRawOptions := util.WriteRawOptions{
  2207  			InitialImageName: imageName,
  2208  			MinimumFreeBytes: request.MinimumFreeBytes,
  2209  			RootLabel:        vm.rootLabel(),
  2210  			RoundupPower:     request.RoundupPower,
  2211  		}
  2212  		err = m.writeRaw(vm.VolumeLocations[0], ".new", client, img.FileSystem,
  2213  			writeRawOptions, request.SkipBootloader)
  2214  		if err != nil {
  2215  			return sendError(conn, err)
  2216  		}
  2217  		if fi, err := os.Stat(tmpRootFilename); err != nil {
  2218  			return sendError(conn, err)
  2219  		} else {
  2220  			newSize = uint64(fi.Size())
  2221  		}
  2222  	} else if request.ImageDataSize > 0 {
  2223  		err := copyData(tmpRootFilename, conn, request.ImageDataSize)
  2224  		if err != nil {
  2225  			return err
  2226  		}
  2227  		newSize = computeSize(request.MinimumFreeBytes, request.RoundupPower,
  2228  			request.ImageDataSize)
  2229  		if err := setVolumeSize(tmpRootFilename, newSize); err != nil {
  2230  			return sendError(conn, err)
  2231  		}
  2232  	} else if request.ImageURL != "" {
  2233  		if err := maybeDrainImage(conn, request.ImageDataSize); err != nil {
  2234  			return err
  2235  		}
  2236  		httpResponse, err := http.Get(request.ImageURL)
  2237  		if err != nil {
  2238  			return sendError(conn, err)
  2239  		}
  2240  		defer httpResponse.Body.Close()
  2241  		if httpResponse.StatusCode != http.StatusOK {
  2242  			return sendError(conn, errors.New(httpResponse.Status))
  2243  		}
  2244  		if httpResponse.ContentLength < 0 {
  2245  			return sendError(conn,
  2246  				errors.New("ContentLength from: "+request.ImageURL))
  2247  		}
  2248  		err = copyData(tmpRootFilename, httpResponse.Body,
  2249  			uint64(httpResponse.ContentLength))
  2250  		if err != nil {
  2251  			return sendError(conn, err)
  2252  		}
  2253  		newSize = computeSize(request.MinimumFreeBytes, request.RoundupPower,
  2254  			uint64(httpResponse.ContentLength))
  2255  		if err := setVolumeSize(tmpRootFilename, newSize); err != nil {
  2256  			return sendError(conn, err)
  2257  		}
  2258  	} else {
  2259  		return sendError(conn, errors.New("no image specified"))
  2260  	}
  2261  	if vm.State == proto.StateRunning {
  2262  		if err := sendUpdate(conn, "stopping VM"); err != nil {
  2263  			return err
  2264  		}
  2265  		stoppedNotifier := make(chan struct{}, 1)
  2266  		vm.stoppedNotifier = stoppedNotifier
  2267  		vm.setState(proto.StateStopping)
  2268  		vm.commandChannel <- "system_powerdown"
  2269  		time.AfterFunc(time.Second*15, vm.kill)
  2270  		vm.mutex.Unlock()
  2271  		<-stoppedNotifier
  2272  		vm.mutex.Lock()
  2273  		if vm.State != proto.StateStopped {
  2274  			restart = false
  2275  			return sendError(conn,
  2276  				errors.New("VM is not stopped after stop attempt"))
  2277  		}
  2278  	}
  2279  	rootFilename := vm.VolumeLocations[0].Filename
  2280  	oldRootFilename := vm.VolumeLocations[0].Filename + ".old"
  2281  	if err := os.Rename(rootFilename, oldRootFilename); err != nil {
  2282  		return sendError(conn, err)
  2283  	}
  2284  	if err := os.Rename(tmpRootFilename, rootFilename); err != nil {
  2285  		os.Rename(oldRootFilename, rootFilename)
  2286  		return sendError(conn, err)
  2287  	}
  2288  	os.Rename(initrdFilename, initrdFilename+".old")
  2289  	os.Rename(tmpInitrdFilename, initrdFilename)
  2290  	os.Rename(kernelFilename, kernelFilename+".old")
  2291  	os.Rename(tmpKernelFilename, kernelFilename)
  2292  	if request.ImageName != "" {
  2293  		vm.ImageName = request.ImageName
  2294  	}
  2295  	vm.Volumes[0].Size = newSize
  2296  	vm.writeAndSendInfo()
  2297  	if restart && vm.State == proto.StateStopped {
  2298  		vm.setState(proto.StateStarting)
  2299  		sendUpdate(conn, "starting VM")
  2300  		vm.mutex.Unlock()
  2301  		_, err := vm.startManaging(-1, false, false)
  2302  		vm.mutex.Lock()
  2303  		if err != nil {
  2304  			sendError(conn, err)
  2305  		}
  2306  	}
  2307  	response := proto.ReplaceVmImageResponse{
  2308  		Final: true,
  2309  	}
  2310  	if err := conn.Encode(response); err != nil {
  2311  		return err
  2312  	}
  2313  	return nil
  2314  }
  2315  
  2316  func (m *Manager) replaceVmUserData(ipAddr net.IP, reader io.Reader,
  2317  	size uint64, authInfo *srpc.AuthInformation) error {
  2318  	vm, err := m.getVmLockAndAuth(ipAddr, true, authInfo, nil)
  2319  	if err != nil {
  2320  		return err
  2321  	}
  2322  	defer vm.mutex.Unlock()
  2323  	filename := filepath.Join(vm.dirname, "user-data.raw")
  2324  	oldFilename := filename + ".old"
  2325  	newFilename := filename + ".new"
  2326  	err = fsutil.CopyToFile(newFilename, privateFilePerms, reader, size)
  2327  	if err != nil {
  2328  		return err
  2329  	}
  2330  	defer os.Remove(newFilename)
  2331  	if err := os.Rename(filename, oldFilename); err != nil {
  2332  		return err
  2333  	}
  2334  	if err := os.Rename(newFilename, filename); err != nil {
  2335  		os.Rename(oldFilename, filename)
  2336  		return err
  2337  	}
  2338  	return nil
  2339  }
  2340  
  2341  func (m *Manager) restoreVmFromSnapshot(ipAddr net.IP,
  2342  	authInfo *srpc.AuthInformation, forceIfNotStopped bool) error {
  2343  	vm, err := m.getVmLockAndAuth(ipAddr, true, authInfo, nil)
  2344  	if err != nil {
  2345  		return err
  2346  	}
  2347  	defer vm.mutex.Unlock()
  2348  	if vm.State != proto.StateStopped {
  2349  		if !forceIfNotStopped {
  2350  			return errors.New("VM is not stopped")
  2351  		}
  2352  	}
  2353  	for _, volume := range vm.VolumeLocations {
  2354  		snapshotFilename := volume.Filename + ".snapshot"
  2355  		if err := os.Rename(snapshotFilename, volume.Filename); err != nil {
  2356  			if !os.IsNotExist(err) {
  2357  				return err
  2358  			}
  2359  		}
  2360  	}
  2361  	return nil
  2362  }
  2363  
  2364  func (m *Manager) restoreVmImage(ipAddr net.IP,
  2365  	authInfo *srpc.AuthInformation) error {
  2366  	vm, err := m.getVmLockAndAuth(ipAddr, true, authInfo, nil)
  2367  	if err != nil {
  2368  		return err
  2369  	}
  2370  	defer vm.mutex.Unlock()
  2371  	if vm.State != proto.StateStopped {
  2372  		return errors.New("VM is not stopped")
  2373  	}
  2374  	rootFilename := vm.VolumeLocations[0].Filename
  2375  	oldRootFilename := vm.VolumeLocations[0].Filename + ".old"
  2376  	fi, err := os.Stat(oldRootFilename)
  2377  	if err != nil {
  2378  		return err
  2379  	}
  2380  	if err := os.Rename(oldRootFilename, rootFilename); err != nil {
  2381  		return err
  2382  	}
  2383  	initrdFilename := vm.getInitrdPath()
  2384  	os.Rename(initrdFilename+".old", initrdFilename)
  2385  	kernelFilename := vm.getKernelPath()
  2386  	os.Rename(kernelFilename+".old", kernelFilename)
  2387  	vm.Volumes[0].Size = uint64(fi.Size())
  2388  	vm.writeAndSendInfo()
  2389  	return nil
  2390  }
  2391  
  2392  func (m *Manager) restoreVmUserData(ipAddr net.IP,
  2393  	authInfo *srpc.AuthInformation) error {
  2394  	vm, err := m.getVmLockAndAuth(ipAddr, true, authInfo, nil)
  2395  	if err != nil {
  2396  		return err
  2397  	}
  2398  	defer vm.mutex.Unlock()
  2399  	filename := filepath.Join(vm.dirname, "user-data.raw")
  2400  	oldFilename := filename + ".old"
  2401  	return os.Rename(oldFilename, filename)
  2402  }
  2403  
  2404  func (m *Manager) scanVmRoot(ipAddr net.IP, authInfo *srpc.AuthInformation,
  2405  	scanFilter *filter.Filter) (*filesystem.FileSystem, error) {
  2406  	vm, err := m.getVmLockAndAuth(ipAddr, false, authInfo, nil)
  2407  	if err != nil {
  2408  		return nil, err
  2409  	}
  2410  	defer vm.mutex.RUnlock()
  2411  	return vm.scanVmRoot(scanFilter)
  2412  }
  2413  
  2414  func (vm *vmInfoType) scanVmRoot(scanFilter *filter.Filter) (
  2415  	*filesystem.FileSystem, error) {
  2416  	if vm.State != proto.StateStopped {
  2417  		return nil, errors.New("VM is not stopped")
  2418  	}
  2419  	rootDir, err := ioutil.TempDir(vm.dirname, "root")
  2420  	if err != nil {
  2421  		return nil, err
  2422  	}
  2423  	defer os.Remove(rootDir)
  2424  	loopDevice, err := fsutil.LoopbackSetup(vm.VolumeLocations[0].Filename)
  2425  	if err != nil {
  2426  		return nil, err
  2427  	}
  2428  	defer fsutil.LoopbackDelete(loopDevice)
  2429  	blockDevice := loopDevice + "p1"
  2430  	vm.logger.Debugf(0, "mounting: %s onto: %s\n", blockDevice, rootDir)
  2431  	err = wsyscall.Mount(blockDevice, rootDir, "ext4", 0, "")
  2432  	if err != nil {
  2433  		return nil, fmt.Errorf("error mounting: %s: %s", blockDevice, err)
  2434  	}
  2435  	defer syscall.Unmount(rootDir, 0)
  2436  	sfs, err := scanner.ScanFileSystem(rootDir, nil, scanFilter, nil, nil, nil)
  2437  	if err != nil {
  2438  		return nil, err
  2439  	}
  2440  	return &sfs.FileSystem, nil
  2441  }
  2442  
  2443  func (m *Manager) sendVmInfo(ipAddress string, vm *proto.VmInfo) {
  2444  	if ipAddress != "0.0.0.0" {
  2445  		if vm == nil { // GOB cannot encode a nil value in a map.
  2446  			vm = new(proto.VmInfo)
  2447  		}
  2448  		m.sendUpdateWithLock(proto.Update{
  2449  			HaveVMs: true,
  2450  			VMs:     map[string]*proto.VmInfo{ipAddress: vm},
  2451  		})
  2452  	}
  2453  }
  2454  
  2455  func (m *Manager) snapshotVm(ipAddr net.IP, authInfo *srpc.AuthInformation,
  2456  	forceIfNotStopped, snapshotRootOnly bool) error {
  2457  	vm, err := m.getVmLockAndAuth(ipAddr, true, authInfo, nil)
  2458  	if err != nil {
  2459  		return err
  2460  	}
  2461  	defer vm.mutex.Unlock()
  2462  	// TODO(rgooch): First check for sufficient free space.
  2463  	if vm.State != proto.StateStopped {
  2464  		if !forceIfNotStopped {
  2465  			return errors.New("VM is not stopped")
  2466  		}
  2467  	}
  2468  	if err := vm.discardSnapshot(); err != nil {
  2469  		return err
  2470  	}
  2471  	doCleanup := true
  2472  	defer func() {
  2473  		if doCleanup {
  2474  			vm.discardSnapshot()
  2475  		}
  2476  	}()
  2477  	for index, volume := range vm.VolumeLocations {
  2478  		snapshotFilename := volume.Filename + ".snapshot"
  2479  		if index == 0 || !snapshotRootOnly {
  2480  			err := fsutil.CopyFile(snapshotFilename, volume.Filename,
  2481  				privateFilePerms)
  2482  			if err != nil {
  2483  				return err
  2484  			}
  2485  		}
  2486  	}
  2487  	doCleanup = false
  2488  	return nil
  2489  }
  2490  
  2491  func (m *Manager) startVm(ipAddr net.IP, authInfo *srpc.AuthInformation,
  2492  	accessToken []byte, dhcpTimeout time.Duration) (bool, error) {
  2493  	vm, err := m.getVmLockAndAuth(ipAddr, true, authInfo, accessToken)
  2494  	if err != nil {
  2495  		return false, err
  2496  	}
  2497  	doUnlock := true
  2498  	defer func() {
  2499  		if doUnlock {
  2500  			vm.mutex.Unlock()
  2501  		}
  2502  	}()
  2503  	if err := checkAvailableMemory(vm.MemoryInMiB); err != nil {
  2504  		return false, err
  2505  	}
  2506  	switch vm.State {
  2507  	case proto.StateStarting:
  2508  		return false, errors.New("VM is already starting")
  2509  	case proto.StateRunning:
  2510  		return false, errors.New("VM is running")
  2511  	case proto.StateStopping:
  2512  		return false, errors.New("VM is stopping")
  2513  	case proto.StateStopped, proto.StateFailedToStart, proto.StateExporting:
  2514  		vm.setState(proto.StateStarting)
  2515  		vm.mutex.Unlock()
  2516  		doUnlock = false
  2517  		return vm.startManaging(dhcpTimeout, false, false)
  2518  	case proto.StateDestroying:
  2519  		return false, errors.New("VM is destroying")
  2520  	case proto.StateMigrating:
  2521  		return false, errors.New("VM is migrating")
  2522  	default:
  2523  		return false, errors.New("unknown state: " + vm.State.String())
  2524  	}
  2525  }
  2526  
  2527  func (m *Manager) stopVm(ipAddr net.IP, authInfo *srpc.AuthInformation,
  2528  	accessToken []byte) error {
  2529  	vm, err := m.getVmLockAndAuth(ipAddr, true, authInfo, accessToken)
  2530  	if err != nil {
  2531  		return err
  2532  	}
  2533  	doUnlock := true
  2534  	defer func() {
  2535  		if doUnlock {
  2536  			vm.mutex.Unlock()
  2537  		}
  2538  	}()
  2539  	switch vm.State {
  2540  	case proto.StateStarting:
  2541  		return errors.New("VM is starting")
  2542  	case proto.StateRunning:
  2543  		if len(vm.Address.IpAddress) < 1 {
  2544  			return errors.New("cannot stop VM with externally managed lease")
  2545  		}
  2546  		stoppedNotifier := make(chan struct{}, 1)
  2547  		vm.stoppedNotifier = stoppedNotifier
  2548  		vm.setState(proto.StateStopping)
  2549  		vm.commandChannel <- "system_powerdown"
  2550  		time.AfterFunc(time.Second*15, vm.kill)
  2551  		vm.mutex.Unlock()
  2552  		doUnlock = false
  2553  		<-stoppedNotifier
  2554  	case proto.StateFailedToStart:
  2555  		vm.setState(proto.StateStopped)
  2556  	case proto.StateStopping:
  2557  		return errors.New("VM is stopping")
  2558  	case proto.StateStopped:
  2559  		return errors.New("VM is already stopped")
  2560  	case proto.StateDestroying:
  2561  		return errors.New("VM is destroying")
  2562  	case proto.StateMigrating:
  2563  		return errors.New("VM is migrating")
  2564  	case proto.StateExporting:
  2565  		return errors.New("VM is exporting")
  2566  	default:
  2567  		return errors.New("unknown state: " + vm.State.String())
  2568  	}
  2569  	return nil
  2570  }
  2571  
  2572  func (m *Manager) unregisterVmMetadataNotifier(ipAddr net.IP,
  2573  	pathChannel chan<- string) error {
  2574  	vm, err := m.getVmAndLock(ipAddr, true)
  2575  	if err != nil {
  2576  		return err
  2577  	}
  2578  	defer vm.mutex.Unlock()
  2579  	delete(vm.metadataChannels, pathChannel)
  2580  	return nil
  2581  }
  2582  
  2583  func (m *Manager) writeRaw(volume proto.LocalVolume, extension string,
  2584  	client *srpc.Client, fs *filesystem.FileSystem,
  2585  	writeRawOptions util.WriteRawOptions, skipBootloader bool) error {
  2586  	var objectsGetter objectserver.ObjectsGetter
  2587  	if m.objectCache == nil {
  2588  		objectClient := objclient.AttachObjectClient(client)
  2589  		defer objectClient.Close()
  2590  		objectsGetter = objectClient
  2591  	} else {
  2592  		objectsGetter = m.objectCache
  2593  	}
  2594  	writeRawOptions.AllocateBlocks = true
  2595  	if skipBootloader {
  2596  		bootInfo, err := util.GetBootInfo(fs, writeRawOptions.RootLabel, "")
  2597  		if err != nil {
  2598  			return err
  2599  		}
  2600  		err = extractKernel(volume, extension, objectsGetter, fs, bootInfo)
  2601  		if err != nil {
  2602  			return err
  2603  		}
  2604  	} else {
  2605  		writeRawOptions.InstallBootloader = true
  2606  	}
  2607  	writeRawOptions.WriteFstab = true
  2608  	return util.WriteRawWithOptions(fs, objectsGetter,
  2609  		volume.Filename+extension, privateFilePerms, mbr.TABLE_TYPE_MSDOS,
  2610  		writeRawOptions, m.Logger)
  2611  }
  2612  
  2613  func (vm *vmInfoType) autoDestroy() {
  2614  	vm.logger.Println("VM was not acknowledged, destroying")
  2615  	authInfo := &srpc.AuthInformation{HaveMethodAccess: true}
  2616  	err := vm.manager.destroyVm(vm.Address.IpAddress, authInfo, nil)
  2617  	if err != nil {
  2618  		vm.logger.Println(err)
  2619  	}
  2620  }
  2621  
  2622  func (vm *vmInfoType) changeIpAddress(ipAddress string) error {
  2623  	dirname := filepath.Join(vm.manager.StateDir, "VMs", ipAddress)
  2624  	if err := os.Rename(vm.dirname, dirname); err != nil {
  2625  		return err
  2626  	}
  2627  	vm.dirname = dirname
  2628  	for index, volume := range vm.VolumeLocations {
  2629  		parent := filepath.Dir(volume.DirectoryToCleanup)
  2630  		dirname := filepath.Join(parent, ipAddress)
  2631  		if err := os.Rename(volume.DirectoryToCleanup, dirname); err != nil {
  2632  			return err
  2633  		}
  2634  		vm.VolumeLocations[index] = proto.LocalVolume{
  2635  			DirectoryToCleanup: dirname,
  2636  			Filename: filepath.Join(dirname,
  2637  				filepath.Base(volume.Filename)),
  2638  		}
  2639  	}
  2640  	vm.logger.Printf("changing to new address: %s\n", ipAddress)
  2641  	vm.logger = prefixlogger.New(ipAddress+": ", vm.manager.Logger)
  2642  	vm.writeInfo()
  2643  	vm.manager.mutex.Lock()
  2644  	defer vm.manager.mutex.Unlock()
  2645  	delete(vm.manager.vms, vm.ipAddress)
  2646  	vm.ipAddress = ipAddress
  2647  	vm.manager.vms[vm.ipAddress] = vm
  2648  	vm.manager.sendUpdateWithLock(proto.Update{
  2649  		HaveVMs: true,
  2650  		VMs:     map[string]*proto.VmInfo{ipAddress: &vm.VmInfo},
  2651  	})
  2652  	return nil
  2653  }
  2654  
  2655  func (vm *vmInfoType) checkAuth(authInfo *srpc.AuthInformation,
  2656  	accessToken []byte) error {
  2657  	if authInfo.HaveMethodAccess {
  2658  		return nil
  2659  	}
  2660  	if _, ok := vm.ownerUsers[authInfo.Username]; ok {
  2661  		return nil
  2662  	}
  2663  	if len(vm.accessToken) >= 32 && bytes.Equal(vm.accessToken, accessToken) {
  2664  		return nil
  2665  	}
  2666  	for _, ownerGroup := range vm.OwnerGroups {
  2667  		if _, ok := authInfo.GroupList[ownerGroup]; ok {
  2668  			return nil
  2669  		}
  2670  	}
  2671  	return errorNoAccessToResource
  2672  }
  2673  
  2674  func (vm *vmInfoType) cleanup() {
  2675  	if vm == nil {
  2676  		return
  2677  	}
  2678  	select {
  2679  	case vm.commandChannel <- "quit":
  2680  	default:
  2681  	}
  2682  	m := vm.manager
  2683  	m.mutex.Lock()
  2684  	delete(m.vms, vm.ipAddress)
  2685  	if !vm.doNotWriteOrSend {
  2686  		m.sendVmInfo(vm.ipAddress, nil)
  2687  	}
  2688  	if !vm.Uncommitted {
  2689  		if err := m.releaseAddressInPoolWithLock(vm.Address); err != nil {
  2690  			m.Logger.Println(err)
  2691  		}
  2692  		for _, address := range vm.SecondaryAddresses {
  2693  			if err := m.releaseAddressInPoolWithLock(address); err != nil {
  2694  				m.Logger.Println(err)
  2695  			}
  2696  		}
  2697  	}
  2698  	os.RemoveAll(vm.dirname)
  2699  	for _, volume := range vm.VolumeLocations {
  2700  		os.RemoveAll(volume.DirectoryToCleanup)
  2701  	}
  2702  	m.mutex.Unlock()
  2703  }
  2704  
  2705  func (vm *vmInfoType) copyRootVolume(request proto.CreateVmRequest,
  2706  	reader io.Reader, dataSize uint64) error {
  2707  	err := vm.setupVolumes(dataSize, request.SecondaryVolumes,
  2708  		request.SpreadVolumes)
  2709  	if err != nil {
  2710  		return err
  2711  	}
  2712  	err = copyData(vm.VolumeLocations[0].Filename, reader, dataSize)
  2713  	if err != nil {
  2714  		return err
  2715  	}
  2716  	vm.Volumes = []proto.Volume{{Size: dataSize}}
  2717  	return nil
  2718  }
  2719  
  2720  func (vm *vmInfoType) delete() {
  2721  	select {
  2722  	case vm.accessTokenCleanupNotifier <- struct{}{}:
  2723  	default:
  2724  	}
  2725  	for ch := range vm.metadataChannels {
  2726  		close(ch)
  2727  	}
  2728  	vm.manager.DhcpServer.RemoveLease(vm.Address.IpAddress)
  2729  	for _, address := range vm.SecondaryAddresses {
  2730  		vm.manager.DhcpServer.RemoveLease(address.IpAddress)
  2731  	}
  2732  	vm.manager.mutex.Lock()
  2733  	delete(vm.manager.vms, vm.ipAddress)
  2734  	vm.manager.sendVmInfo(vm.ipAddress, nil)
  2735  	var err error
  2736  	if vm.State == proto.StateExporting {
  2737  		err = vm.manager.unregisterAddress(vm.Address, false)
  2738  		for _, address := range vm.SecondaryAddresses {
  2739  			err := vm.manager.unregisterAddress(address, false)
  2740  			if err != nil {
  2741  				vm.manager.Logger.Println(err)
  2742  			}
  2743  		}
  2744  	} else if !vm.Uncommitted {
  2745  		err = vm.manager.releaseAddressInPoolWithLock(vm.Address)
  2746  		for _, address := range vm.SecondaryAddresses {
  2747  			err := vm.manager.releaseAddressInPoolWithLock(address)
  2748  			if err != nil {
  2749  				vm.manager.Logger.Println(err)
  2750  			}
  2751  		}
  2752  	}
  2753  	vm.manager.mutex.Unlock()
  2754  	if err != nil {
  2755  		vm.manager.Logger.Println(err)
  2756  	}
  2757  	for _, volume := range vm.VolumeLocations {
  2758  		os.Remove(volume.Filename)
  2759  		if volume.DirectoryToCleanup != "" {
  2760  			os.RemoveAll(volume.DirectoryToCleanup)
  2761  		}
  2762  	}
  2763  	os.RemoveAll(vm.dirname)
  2764  }
  2765  
  2766  func (vm *vmInfoType) destroy() {
  2767  	select {
  2768  	case vm.commandChannel <- "quit":
  2769  	default:
  2770  	}
  2771  	vm.delete()
  2772  }
  2773  
  2774  func (vm *vmInfoType) discardSnapshot() error {
  2775  	for _, volume := range vm.VolumeLocations {
  2776  		if err := os.Remove(volume.Filename + ".snapshot"); err != nil {
  2777  			if !os.IsNotExist(err) {
  2778  				return err
  2779  			}
  2780  		}
  2781  	}
  2782  	return nil
  2783  }
  2784  
  2785  func (vm *vmInfoType) getActiveInitrdPath() string {
  2786  	initrdPath := vm.getInitrdPath()
  2787  	if _, err := os.Stat(initrdPath); err == nil {
  2788  		return initrdPath
  2789  	}
  2790  	return ""
  2791  }
  2792  
  2793  func (vm *vmInfoType) getActiveKernelPath() string {
  2794  	kernelPath := vm.getKernelPath()
  2795  	if _, err := os.Stat(kernelPath); err == nil {
  2796  		return kernelPath
  2797  	}
  2798  	return ""
  2799  }
  2800  
  2801  func (vm *vmInfoType) getInitrdPath() string {
  2802  	return filepath.Join(vm.VolumeLocations[0].DirectoryToCleanup, "initrd")
  2803  }
  2804  
  2805  func (vm *vmInfoType) getKernelPath() string {
  2806  	return filepath.Join(vm.VolumeLocations[0].DirectoryToCleanup, "kernel")
  2807  }
  2808  
  2809  func (vm *vmInfoType) kill() {
  2810  	vm.mutex.RLock()
  2811  	defer vm.mutex.RUnlock()
  2812  	if vm.State == proto.StateStopping {
  2813  		vm.commandChannel <- "quit"
  2814  	}
  2815  }
  2816  
  2817  func (vm *vmInfoType) monitor(monitorSock net.Conn,
  2818  	commandChannel <-chan string) {
  2819  	vm.hasHealthAgent = false
  2820  	defer monitorSock.Close()
  2821  	go vm.processMonitorResponses(monitorSock)
  2822  	cancelChannel := make(chan struct{}, 1)
  2823  	go vm.probeHealthAgent(cancelChannel)
  2824  	go vm.serialManager()
  2825  	for command := range commandChannel {
  2826  		_, err := fmt.Fprintf(monitorSock, `{"execute":"%s"}`, command)
  2827  		if err != nil {
  2828  			vm.logger.Println(err)
  2829  		} else {
  2830  			vm.logger.Debugf(0, "sent %s command", command)
  2831  		}
  2832  	}
  2833  	cancelChannel <- struct{}{}
  2834  }
  2835  
  2836  func (vm *vmInfoType) probeHealthAgent(cancel <-chan struct{}) {
  2837  	stopTime := time.Now().Add(time.Minute * 5)
  2838  	for time.Until(stopTime) > 0 {
  2839  		select {
  2840  		case <-cancel:
  2841  			return
  2842  		default:
  2843  		}
  2844  		sleepUntil := time.Now().Add(time.Second)
  2845  		if vm.ipAddress == "0.0.0.0" {
  2846  			time.Sleep(time.Until(sleepUntil))
  2847  			continue
  2848  		}
  2849  		conn, err := net.DialTimeout("tcp", vm.ipAddress+":6910", time.Second*5)
  2850  		if err == nil {
  2851  			conn.Close()
  2852  			vm.mutex.Lock()
  2853  			vm.hasHealthAgent = true
  2854  			vm.mutex.Unlock()
  2855  			return
  2856  		}
  2857  		time.Sleep(time.Until(sleepUntil))
  2858  	}
  2859  }
  2860  
  2861  func (vm *vmInfoType) processMonitorResponses(monitorSock net.Conn) {
  2862  	io.Copy(ioutil.Discard, monitorSock) // Read all and drop.
  2863  	vm.mutex.Lock()
  2864  	defer vm.mutex.Unlock()
  2865  	close(vm.commandChannel)
  2866  	vm.commandChannel = nil
  2867  	switch vm.State {
  2868  	case proto.StateStarting:
  2869  		select {
  2870  		case vm.stoppedNotifier <- struct{}{}:
  2871  		default:
  2872  		}
  2873  		return
  2874  	case proto.StateRunning:
  2875  		select {
  2876  		case vm.stoppedNotifier <- struct{}{}:
  2877  		default:
  2878  		}
  2879  		return
  2880  	case proto.StateFailedToStart:
  2881  		return
  2882  	case proto.StateStopping:
  2883  		vm.setState(proto.StateStopped)
  2884  		select {
  2885  		case vm.stoppedNotifier <- struct{}{}:
  2886  		default:
  2887  		}
  2888  	case proto.StateStopped:
  2889  		return
  2890  	case proto.StateDestroying:
  2891  		vm.delete()
  2892  		return
  2893  	case proto.StateMigrating:
  2894  		return
  2895  	case proto.StateExporting:
  2896  		return
  2897  	default:
  2898  		vm.logger.Println("unknown state: " + vm.State.String())
  2899  	}
  2900  }
  2901  
  2902  func (vm *vmInfoType) rootLabel() string {
  2903  	ipAddr := vm.Address.IpAddress
  2904  	return fmt.Sprintf("rootfs@%02x%02x%02x%02x",
  2905  		ipAddr[0], ipAddr[1], ipAddr[2], ipAddr[3])
  2906  }
  2907  
  2908  func (vm *vmInfoType) serialManager() {
  2909  	bootlogFile, err := os.OpenFile(filepath.Join(vm.dirname, bootlogFilename),
  2910  		os.O_CREATE|os.O_WRONLY|os.O_APPEND, fsutil.PublicFilePerms)
  2911  	if err != nil {
  2912  		vm.logger.Printf("error opening bootlog file: %s\n", err)
  2913  		return
  2914  	}
  2915  	defer bootlogFile.Close()
  2916  	serialSock, err := net.Dial("unix",
  2917  		filepath.Join(vm.dirname, serialSockFilename))
  2918  	if err != nil {
  2919  		vm.logger.Printf("error connecting to console: %s\n", err)
  2920  		return
  2921  	}
  2922  	defer serialSock.Close()
  2923  	vm.mutex.Lock()
  2924  	vm.serialInput = serialSock
  2925  	vm.mutex.Unlock()
  2926  	buffer := make([]byte, 256)
  2927  	for {
  2928  		if nRead, err := serialSock.Read(buffer); err != nil {
  2929  			if err != io.EOF {
  2930  				vm.logger.Printf("error reading from serial port: %s\n", err)
  2931  			} else {
  2932  				vm.logger.Debugln(0, "serial port closed")
  2933  			}
  2934  			break
  2935  		} else if nRead > 0 {
  2936  			vm.mutex.RLock()
  2937  			if vm.serialOutput != nil {
  2938  				for _, char := range buffer[:nRead] {
  2939  					vm.serialOutput <- char
  2940  				}
  2941  				vm.mutex.RUnlock()
  2942  			} else {
  2943  				vm.mutex.RUnlock()
  2944  				bootlogFile.Write(buffer[:nRead])
  2945  			}
  2946  		}
  2947  	}
  2948  	vm.mutex.Lock()
  2949  	vm.serialInput = nil
  2950  	if vm.serialOutput != nil {
  2951  		close(vm.serialOutput)
  2952  		vm.serialOutput = nil
  2953  	}
  2954  	vm.mutex.Unlock()
  2955  }
  2956  
  2957  func (vm *vmInfoType) setState(state proto.State) {
  2958  	vm.State = state
  2959  	if !vm.doNotWriteOrSend {
  2960  		vm.writeAndSendInfo()
  2961  	}
  2962  }
  2963  
  2964  func (vm *vmInfoType) setupVolumes(rootSize uint64,
  2965  	secondaryVolumes []proto.Volume, spreadVolumes bool) error {
  2966  	volumeDirectories, err := vm.manager.getVolumeDirectories(rootSize,
  2967  		secondaryVolumes, spreadVolumes)
  2968  	if err != nil {
  2969  		return err
  2970  	}
  2971  	volumeDirectory := filepath.Join(volumeDirectories[0], vm.ipAddress)
  2972  	os.RemoveAll(volumeDirectory)
  2973  	if err := os.MkdirAll(volumeDirectory, dirPerms); err != nil {
  2974  		return err
  2975  	}
  2976  	filename := filepath.Join(volumeDirectory, "root")
  2977  	vm.VolumeLocations = append(vm.VolumeLocations,
  2978  		proto.LocalVolume{volumeDirectory, filename})
  2979  	for index := range secondaryVolumes {
  2980  		volumeDirectory := filepath.Join(volumeDirectories[index+1],
  2981  			vm.ipAddress)
  2982  		os.RemoveAll(volumeDirectory)
  2983  		if err := os.MkdirAll(volumeDirectory, dirPerms); err != nil {
  2984  			return err
  2985  		}
  2986  		filename := filepath.Join(volumeDirectory,
  2987  			fmt.Sprintf("secondary-volume.%d", index))
  2988  		vm.VolumeLocations = append(vm.VolumeLocations,
  2989  			proto.LocalVolume{volumeDirectory, filename})
  2990  	}
  2991  	return nil
  2992  }
  2993  
  2994  // This may grab the VM lock.
  2995  func (vm *vmInfoType) startManaging(dhcpTimeout time.Duration,
  2996  	enableNetboot, haveManagerLock bool) (bool, error) {
  2997  	vm.monitorSockname = filepath.Join(vm.dirname, "monitor.sock")
  2998  	vm.logger.Debugln(1, "startManaging() starting")
  2999  	switch vm.State {
  3000  	case proto.StateStarting:
  3001  	case proto.StateRunning:
  3002  	case proto.StateFailedToStart:
  3003  	case proto.StateStopping:
  3004  		monitorSock, err := net.Dial("unix", vm.monitorSockname)
  3005  		if err == nil {
  3006  			commandChannel := make(chan string, 1)
  3007  			vm.commandChannel = commandChannel
  3008  			go vm.monitor(monitorSock, commandChannel)
  3009  			commandChannel <- "qmp_capabilities"
  3010  			vm.kill()
  3011  		}
  3012  		return false, nil
  3013  	case proto.StateStopped:
  3014  		return false, nil
  3015  	case proto.StateDestroying:
  3016  		vm.delete()
  3017  		return false, nil
  3018  	case proto.StateMigrating:
  3019  		return false, nil
  3020  	default:
  3021  		vm.logger.Println("unknown state: " + vm.State.String())
  3022  		return false, nil
  3023  	}
  3024  	if dhcpTimeout >= 0 {
  3025  		err := vm.manager.DhcpServer.AddLease(vm.Address, vm.Hostname)
  3026  		if err != nil {
  3027  			return false, err
  3028  		}
  3029  		for _, address := range vm.SecondaryAddresses {
  3030  			err := vm.manager.DhcpServer.AddLease(address, vm.Hostname)
  3031  			if err != nil {
  3032  				vm.logger.Println(err)
  3033  			}
  3034  		}
  3035  	}
  3036  	monitorSock, err := net.Dial("unix", vm.monitorSockname)
  3037  	if err != nil {
  3038  		vm.logger.Debugf(1, "error connecting to: %s: %s\n",
  3039  			vm.monitorSockname, err)
  3040  		if err := vm.startVm(enableNetboot, haveManagerLock); err != nil {
  3041  			vm.logger.Println(err)
  3042  			vm.setState(proto.StateFailedToStart)
  3043  			return false, err
  3044  		}
  3045  		monitorSock, err = net.Dial("unix", vm.monitorSockname)
  3046  	}
  3047  	if err != nil {
  3048  		vm.logger.Println(err)
  3049  		vm.setState(proto.StateFailedToStart)
  3050  		return false, err
  3051  	}
  3052  	commandChannel := make(chan string, 1)
  3053  	vm.commandChannel = commandChannel
  3054  	go vm.monitor(monitorSock, commandChannel)
  3055  	commandChannel <- "qmp_capabilities"
  3056  	vm.setState(proto.StateRunning)
  3057  	if len(vm.Address.IpAddress) < 1 {
  3058  		// Must wait to see what IP address is given by external DHCP server.
  3059  		reqCh := vm.manager.DhcpServer.MakeRequestChannel(vm.Address.MacAddress)
  3060  		if dhcpTimeout < time.Minute {
  3061  			dhcpTimeout = time.Minute
  3062  		}
  3063  		timer := time.NewTimer(dhcpTimeout)
  3064  		select {
  3065  		case ipAddr := <-reqCh:
  3066  			timer.Stop()
  3067  			return false, vm.changeIpAddress(ipAddr.String())
  3068  		case <-timer.C:
  3069  			return true, errors.New("timed out on external lease")
  3070  		}
  3071  	}
  3072  	if dhcpTimeout > 0 {
  3073  		ackChan := vm.manager.DhcpServer.MakeAcknowledgmentChannel(
  3074  			vm.Address.IpAddress)
  3075  		timer := time.NewTimer(dhcpTimeout)
  3076  		select {
  3077  		case <-ackChan:
  3078  			timer.Stop()
  3079  		case <-timer.C:
  3080  			return true, nil
  3081  		}
  3082  	}
  3083  	return false, nil
  3084  }
  3085  
  3086  func (vm *vmInfoType) getBridgesAndOptions(haveManagerLock bool) (
  3087  	[]string, []string, error) {
  3088  	if !haveManagerLock {
  3089  		vm.manager.mutex.RLock()
  3090  		defer vm.manager.mutex.RUnlock()
  3091  	}
  3092  	addresses := make([]proto.Address, 1, len(vm.SecondarySubnetIDs)+1)
  3093  	addresses[0] = vm.Address
  3094  	subnetIDs := make([]string, 1, len(vm.SecondarySubnetIDs)+1)
  3095  	subnetIDs[0] = vm.SubnetId
  3096  	for index, subnetId := range vm.SecondarySubnetIDs {
  3097  		addresses = append(addresses, vm.SecondaryAddresses[index])
  3098  		subnetIDs = append(subnetIDs, subnetId)
  3099  	}
  3100  	var bridges, options []string
  3101  	deviceDriver := "virtio-net-pci"
  3102  	if vm.DisableVirtIO {
  3103  		deviceDriver = "e1000"
  3104  	}
  3105  	for index, address := range addresses {
  3106  		subnet, ok := vm.manager.subnets[subnetIDs[index]]
  3107  		if !ok {
  3108  			return nil, nil,
  3109  				fmt.Errorf("subnet: %s not found", subnetIDs[index])
  3110  		}
  3111  		bridge, vlanOption, err := vm.manager.getBridgeForSubnet(subnet)
  3112  		if err != nil {
  3113  			return nil, nil, err
  3114  		}
  3115  		bridges = append(bridges, bridge)
  3116  		options = append(options,
  3117  			"-netdev", fmt.Sprintf("tap,id=net%d,fd=%d%s",
  3118  				index, index+3, vlanOption),
  3119  			"-device", fmt.Sprintf("%s,netdev=net%d,mac=%s",
  3120  				deviceDriver, index, address.MacAddress))
  3121  	}
  3122  	return bridges, options, nil
  3123  }
  3124  
  3125  func (vm *vmInfoType) startVm(enableNetboot, haveManagerLock bool) error {
  3126  	if err := checkAvailableMemory(vm.MemoryInMiB); err != nil {
  3127  		return err
  3128  	}
  3129  	nCpus := vm.MilliCPUs / 1000
  3130  	if nCpus < 1 {
  3131  		nCpus = 1
  3132  	}
  3133  	if nCpus*1000 < vm.MilliCPUs {
  3134  		nCpus++
  3135  	}
  3136  	bridges, netOptions, err := vm.getBridgesAndOptions(haveManagerLock)
  3137  	if err != nil {
  3138  		return err
  3139  	}
  3140  	var tapFiles []*os.File
  3141  	for _, bridge := range bridges {
  3142  		tapFile, err := createTapDevice(bridge)
  3143  		if err != nil {
  3144  			return fmt.Errorf("error creating tap device: %s", err)
  3145  		}
  3146  		defer tapFile.Close()
  3147  		tapFiles = append(tapFiles, tapFile)
  3148  	}
  3149  	cmd := exec.Command("qemu-system-x86_64", "-machine", "pc,accel=kvm",
  3150  		"-cpu", "host", // Allow the VM to take full advantage of host CPU.
  3151  		"-nodefaults",
  3152  		"-name", vm.ipAddress,
  3153  		"-m", fmt.Sprintf("%dM", vm.MemoryInMiB),
  3154  		"-smp", fmt.Sprintf("cpus=%d", nCpus),
  3155  		"-serial",
  3156  		"unix:"+filepath.Join(vm.dirname, serialSockFilename)+",server,nowait",
  3157  		"-chroot", "/tmp",
  3158  		"-runas", vm.manager.Username,
  3159  		"-qmp", "unix:"+vm.monitorSockname+",server,nowait",
  3160  		"-daemonize")
  3161  	if kernelPath := vm.getActiveKernelPath(); kernelPath != "" {
  3162  		cmd.Args = append(cmd.Args, "-kernel", kernelPath)
  3163  		if initrdPath := vm.getActiveInitrdPath(); initrdPath != "" {
  3164  			cmd.Args = append(cmd.Args,
  3165  				"-initrd", initrdPath,
  3166  				"-append", util.MakeKernelOptions("LABEL="+vm.rootLabel(),
  3167  					"net.ifnames=0"),
  3168  			)
  3169  		} else {
  3170  			cmd.Args = append(cmd.Args,
  3171  				"-append", util.MakeKernelOptions("/dev/vda1", "net.ifnames=0"),
  3172  			)
  3173  		}
  3174  	} else if enableNetboot {
  3175  		cmd.Args = append(cmd.Args, "-boot", "order=n")
  3176  	}
  3177  	cmd.Args = append(cmd.Args, netOptions...)
  3178  	if vm.manager.ShowVgaConsole {
  3179  		cmd.Args = append(cmd.Args, "-vga", "std")
  3180  	} else {
  3181  		switch vm.ConsoleType {
  3182  		case proto.ConsoleNone:
  3183  			cmd.Args = append(cmd.Args, "-nographic")
  3184  		case proto.ConsoleDummy:
  3185  			cmd.Args = append(cmd.Args, "-display", "none", "-vga", "std")
  3186  		case proto.ConsoleVNC:
  3187  			cmd.Args = append(cmd.Args,
  3188  				"-display", "vnc=unix:"+filepath.Join(vm.dirname, "vnc"),
  3189  				"-vga", "std")
  3190  		}
  3191  	}
  3192  	var interfaceDriver string
  3193  	if !vm.DisableVirtIO {
  3194  		interfaceDriver = ",if=virtio"
  3195  	}
  3196  	for index, volume := range vm.VolumeLocations {
  3197  		var volumeFormat proto.VolumeFormat
  3198  		if index < len(vm.Volumes) {
  3199  			volumeFormat = vm.Volumes[index].Format
  3200  		}
  3201  		options := interfaceDriver
  3202  		if vm.manager.checkTrim(volume.Filename) {
  3203  			options += ",discard=on"
  3204  		}
  3205  		cmd.Args = append(cmd.Args,
  3206  			"-drive", "file="+volume.Filename+",format="+volumeFormat.String()+
  3207  				options)
  3208  	}
  3209  	os.Remove(filepath.Join(vm.dirname, "bootlog"))
  3210  	cmd.ExtraFiles = tapFiles // Start at fd=3 for QEMU.
  3211  	if output, err := cmd.CombinedOutput(); err != nil {
  3212  		return fmt.Errorf("error starting QEMU: %s: %s", err, output)
  3213  	} else if len(output) > 0 {
  3214  		vm.logger.Printf("QEMU started. Output: \"%s\"\n", string(output))
  3215  	} else {
  3216  		vm.logger.Println("QEMU started.")
  3217  	}
  3218  	return nil
  3219  }
  3220  
  3221  func (vm *vmInfoType) writeAndSendInfo() {
  3222  	if err := vm.writeInfo(); err != nil {
  3223  		vm.logger.Println(err)
  3224  		return
  3225  	}
  3226  	vm.manager.sendVmInfo(vm.ipAddress, &vm.VmInfo)
  3227  }
  3228  
  3229  func (vm *vmInfoType) writeInfo() error {
  3230  	filename := filepath.Join(vm.dirname, "info.json")
  3231  	return json.WriteToFile(filename, publicFilePerms, "    ", vm)
  3232  }