github.com/Cloud-Foundations/Dominator@v0.3.4/hypervisor/client/impl.go (about)

     1  package client
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io"
     7  	"net"
     8  	"os"
     9  	"os/exec"
    10  	"sort"
    11  	"time"
    12  
    13  	"github.com/Cloud-Foundations/Dominator/lib/bufwriter"
    14  	"github.com/Cloud-Foundations/Dominator/lib/errors"
    15  	"github.com/Cloud-Foundations/Dominator/lib/filesystem"
    16  	"github.com/Cloud-Foundations/Dominator/lib/filter"
    17  	"github.com/Cloud-Foundations/Dominator/lib/log"
    18  	"github.com/Cloud-Foundations/Dominator/lib/srpc"
    19  	proto "github.com/Cloud-Foundations/Dominator/proto/hypervisor"
    20  )
    21  
    22  func acknowledgeVm(client *srpc.Client, ipAddress net.IP) error {
    23  	request := proto.AcknowledgeVmRequest{ipAddress}
    24  	var reply proto.AcknowledgeVmResponse
    25  	return client.RequestReply("Hypervisor.AcknowledgeVm", request, &reply)
    26  }
    27  
    28  func addVmVolumes(client *srpc.Client, ipAddress net.IP, sizes []uint64) error {
    29  	request := proto.AddVmVolumesRequest{
    30  		IpAddress:   ipAddress,
    31  		VolumeSizes: sizes,
    32  	}
    33  	var reply proto.AddVmVolumesResponse
    34  	err := client.RequestReply("Hypervisor.AddVmVolumes", request, &reply)
    35  	if err != nil {
    36  		return err
    37  	}
    38  	return errors.New(reply.Error)
    39  }
    40  
    41  func changeVmSize(client *srpc.Client,
    42  	request proto.ChangeVmSizeRequest) error {
    43  	var reply proto.ChangeVmSizeResponse
    44  	err := client.RequestReply("Hypervisor.ChangeVmSize", request, &reply)
    45  	if err != nil {
    46  		return err
    47  	}
    48  	return errors.New(reply.Error)
    49  }
    50  
    51  func changeVmVolumeSize(client *srpc.Client, ipAddress net.IP, index uint,
    52  	size uint64) error {
    53  	request := proto.ChangeVmVolumeSizeRequest{
    54  		IpAddress:   ipAddress,
    55  		VolumeIndex: index,
    56  		VolumeSize:  size,
    57  	}
    58  	var reply proto.ChangeVmVolumeSizeResponse
    59  	err := client.RequestReply("Hypervisor.ChangeVmVolumeSize", request, &reply)
    60  	if err != nil {
    61  		return err
    62  	}
    63  	return errors.New(reply.Error)
    64  }
    65  
    66  func connectToVmConsole(client *srpc.Client, ipAddr net.IP,
    67  	vncViewerCommand string, logger log.DebugLogger) error {
    68  	serverConn, err := client.Call("Hypervisor.ConnectToVmConsole")
    69  	if err != nil {
    70  		return err
    71  	}
    72  	defer serverConn.Close()
    73  	request := proto.ConnectToVmConsoleRequest{IpAddress: ipAddr}
    74  	if err := serverConn.Encode(request); err != nil {
    75  		return err
    76  	}
    77  	if err := serverConn.Flush(); err != nil {
    78  		return err
    79  	}
    80  	var response proto.ConnectToVmConsoleResponse
    81  	if err := serverConn.Decode(&response); err != nil {
    82  		return err
    83  	}
    84  	if err := errors.New(response.Error); err != nil {
    85  		return err
    86  	}
    87  	listener, err := net.Listen("tcp", "localhost:")
    88  	if err != nil {
    89  		return err
    90  	}
    91  	defer listener.Close()
    92  	_, port, err := net.SplitHostPort(listener.Addr().String())
    93  	if err != nil {
    94  		return err
    95  	}
    96  	if vncViewerCommand == "" {
    97  		logger.Printf("listening on port %s for VNC connection\n", port)
    98  	} else {
    99  		cmd := exec.Command(vncViewerCommand, "::"+port)
   100  		cmd.Stderr = os.Stderr
   101  		if err := cmd.Start(); err != nil {
   102  			return err
   103  		}
   104  	}
   105  	clientConn, err := listener.Accept()
   106  	if err != nil {
   107  		return err
   108  	}
   109  	defer clientConn.Close()
   110  	listener.Close()
   111  	var readErr error
   112  	readFinished := false
   113  	go func() { // Copy from server to client.
   114  		_, readErr = io.Copy(clientConn, serverConn)
   115  		readFinished = true
   116  	}()
   117  	// Copy from client to server.
   118  	_, writeErr := io.Copy(bufwriter.NewAutoFlushWriter(serverConn), clientConn)
   119  	if readFinished {
   120  		return readErr
   121  	}
   122  	return writeErr
   123  }
   124  
   125  func createVm(client *srpc.Client, request proto.CreateVmRequest,
   126  	reply *proto.CreateVmResponse, logger log.DebugLogger) error {
   127  	if conn, err := client.Call("Hypervisor.CreateVm"); err != nil {
   128  		return err
   129  	} else {
   130  		defer conn.Close()
   131  		if err := conn.Encode(request); err != nil {
   132  			return err
   133  		}
   134  		if err := conn.Flush(); err != nil {
   135  			return err
   136  		}
   137  		for {
   138  			var response proto.CreateVmResponse
   139  			if err := conn.Decode(&response); err != nil {
   140  				return fmt.Errorf("error decoding: %s", err)
   141  			}
   142  			if response.Error != "" {
   143  				return errors.New(response.Error)
   144  			}
   145  			if response.ProgressMessage != "" {
   146  				logger.Debugln(0, response.ProgressMessage)
   147  			}
   148  			if response.Final {
   149  				*reply = response
   150  				return nil
   151  			}
   152  		}
   153  	}
   154  }
   155  
   156  func deleteVmVolume(client *srpc.Client, ipAddr net.IP, accessToken []byte,
   157  	volumeIndex uint) error {
   158  	request := proto.DeleteVmVolumeRequest{
   159  		AccessToken: accessToken,
   160  		IpAddress:   ipAddr,
   161  		VolumeIndex: volumeIndex,
   162  	}
   163  	var reply proto.DeleteVmVolumeResponse
   164  	err := client.RequestReply("Hypervisor.DeleteVmVolume", request, &reply)
   165  	if err != nil {
   166  		return err
   167  	}
   168  	return errors.New(reply.Error)
   169  }
   170  
   171  func destroyVm(client *srpc.Client, ipAddr net.IP, accessToken []byte) error {
   172  	request := proto.DestroyVmRequest{
   173  		AccessToken: accessToken,
   174  		IpAddress:   ipAddr,
   175  	}
   176  	var reply proto.DestroyVmResponse
   177  	err := client.RequestReply("Hypervisor.DestroyVm", request, &reply)
   178  	if err != nil {
   179  		return err
   180  	}
   181  	return errors.New(reply.Error)
   182  }
   183  
   184  func exportLocalVm(client *srpc.Client, ipAddr net.IP,
   185  	verificationCookie []byte) (proto.ExportLocalVmInfo, error) {
   186  	request := proto.ExportLocalVmRequest{
   187  		IpAddress:          ipAddr,
   188  		VerificationCookie: verificationCookie,
   189  	}
   190  	var reply proto.ExportLocalVmResponse
   191  	err := client.RequestReply("Hypervisor.ExportLocalVm", request, &reply)
   192  	if err != nil {
   193  		return proto.ExportLocalVmInfo{}, err
   194  	}
   195  	if err := errors.New(reply.Error); err != nil {
   196  		return proto.ExportLocalVmInfo{}, err
   197  	}
   198  	return reply.VmInfo, nil
   199  }
   200  
   201  func getCapacity(client *srpc.Client) (proto.GetCapacityResponse, error) {
   202  	request := proto.GetCapacityRequest{}
   203  	var reply proto.GetCapacityResponse
   204  	err := client.RequestReply("Hypervisor.GetCapacity", request, &reply)
   205  	if err != nil {
   206  		return proto.GetCapacityResponse{}, err
   207  	}
   208  	return reply, nil
   209  }
   210  
   211  func getRootCookiePath(client *srpc.Client) (string, error) {
   212  	request := proto.GetRootCookiePathRequest{}
   213  	var reply proto.GetRootCookiePathResponse
   214  	err := client.RequestReply("Hypervisor.GetRootCookiePath", request, &reply)
   215  	if err != nil {
   216  		return "", err
   217  	}
   218  	if err := errors.New(reply.Error); err != nil {
   219  		return "", err
   220  	}
   221  	return reply.Path, nil
   222  }
   223  
   224  func getVmInfo(client *srpc.Client, ipAddr net.IP) (proto.VmInfo, error) {
   225  	request := proto.GetVmInfoRequest{IpAddress: ipAddr}
   226  	var reply proto.GetVmInfoResponse
   227  	err := client.RequestReply("Hypervisor.GetVmInfo", request, &reply)
   228  	if err != nil {
   229  		return proto.VmInfo{}, err
   230  	}
   231  	if err := errors.New(reply.Error); err != nil {
   232  		return proto.VmInfo{}, err
   233  	}
   234  	return reply.VmInfo, nil
   235  }
   236  
   237  func getVmLastPatchLog(client *srpc.Client, ipAddr net.IP) (
   238  	[]byte, time.Time, error) {
   239  	conn, err := client.Call("Hypervisor.GetVmLastPatchLog")
   240  	if err != nil {
   241  		return nil, time.Time{}, err
   242  	}
   243  	defer conn.Close()
   244  	request := proto.GetVmLastPatchLogRequest{IpAddress: ipAddr}
   245  	if err := conn.Encode(request); err != nil {
   246  		return nil, time.Time{}, err
   247  	}
   248  	if err := conn.Flush(); err != nil {
   249  		return nil, time.Time{}, err
   250  	}
   251  	var response proto.GetVmLastPatchLogResponse
   252  	if err := conn.Decode(&response); err != nil {
   253  		return nil, time.Time{}, err
   254  	}
   255  	if err := errors.New(response.Error); err != nil {
   256  		return nil, time.Time{}, err
   257  	}
   258  	buffer := &bytes.Buffer{}
   259  	if _, err := io.CopyN(buffer, conn, int64(response.Length)); err != nil {
   260  		return nil, time.Time{}, err
   261  	}
   262  	return buffer.Bytes(), response.PatchTime, nil
   263  }
   264  
   265  func holdLock(client *srpc.Client, timeout time.Duration,
   266  	writeLock bool) error {
   267  	request := proto.HoldLockRequest{timeout, writeLock}
   268  	var reply proto.HoldLockResponse
   269  	err := client.RequestReply("Hypervisor.HoldLock", request, &reply)
   270  	if err != nil {
   271  		return err
   272  	}
   273  	return errors.New(reply.Error)
   274  }
   275  
   276  func holdVmLock(client *srpc.Client, ipAddr net.IP, timeout time.Duration,
   277  	writeLock bool) error {
   278  	request := proto.HoldVmLockRequest{ipAddr, timeout, writeLock}
   279  	var reply proto.HoldVmLockResponse
   280  	err := client.RequestReply("Hypervisor.HoldVmLock", request, &reply)
   281  	if err != nil {
   282  		return err
   283  	}
   284  	return errors.New(reply.Error)
   285  }
   286  
   287  func listSubnets(client *srpc.Client, doSort bool) ([]proto.Subnet, error) {
   288  	request := proto.ListSubnetsRequest{Sort: doSort}
   289  	var reply proto.ListSubnetsResponse
   290  	err := client.RequestReply("Hypervisor.ListSubnets", request, &reply)
   291  	if err != nil {
   292  		return nil, err
   293  	}
   294  	if err := errors.New(reply.Error); err != nil {
   295  		return nil, err
   296  	}
   297  	return reply.Subnets, nil
   298  }
   299  
   300  func listVolumeDirectories(client *srpc.Client, doSort bool) ([]string, error) {
   301  	var request proto.ListVolumeDirectoriesRequest
   302  	var reply proto.ListVolumeDirectoriesResponse
   303  	err := client.RequestReply("Hypervisor.ListVolumeDirectories", request,
   304  		&reply)
   305  	if err != nil {
   306  		return nil, err
   307  	}
   308  	if err := errors.New(reply.Error); err != nil {
   309  		return nil, err
   310  	}
   311  	if doSort {
   312  		sort.Strings(reply.Directories)
   313  	}
   314  	return reply.Directories, nil
   315  }
   316  
   317  func powerOff(client *srpc.Client, stopVMs bool) error {
   318  	request := proto.PowerOffRequest{StopVMs: stopVMs}
   319  	var reply proto.PowerOffResponse
   320  	err := client.RequestReply("Hypervisor.PowerOff", request, &reply)
   321  	if err != nil {
   322  		return err
   323  	}
   324  	return errors.New(reply.Error)
   325  }
   326  
   327  func prepareVmForMigration(client *srpc.Client, ipAddr net.IP,
   328  	accessToken []byte, enable bool) error {
   329  	request := proto.PrepareVmForMigrationRequest{
   330  		AccessToken: accessToken,
   331  		Enable:      enable,
   332  		IpAddress:   ipAddr,
   333  	}
   334  	var reply proto.PrepareVmForMigrationResponse
   335  	err := client.RequestReply("Hypervisor.PrepareVmForMigration",
   336  		request, &reply)
   337  	if err != nil {
   338  		return err
   339  	}
   340  	return errors.New(reply.Error)
   341  }
   342  
   343  func registerExternalLeases(client *srpc.Client, addressList proto.AddressList,
   344  	hostnames []string) error {
   345  	request := proto.RegisterExternalLeasesRequest{
   346  		Addresses: addressList,
   347  		Hostnames: hostnames,
   348  	}
   349  	var reply proto.RegisterExternalLeasesResponse
   350  	err := client.RequestReply("Hypervisor.RegisterExternalLeases",
   351  		request, &reply)
   352  	if err != nil {
   353  		return err
   354  	}
   355  	return errors.New(reply.Error)
   356  }
   357  
   358  func reorderVmVolumes(client *srpc.Client, ipAddr net.IP, accessToken []byte,
   359  	volumeIndices []uint) error {
   360  	request := proto.ReorderVmVolumesRequest{
   361  		IpAddress:     ipAddr,
   362  		VolumeIndices: volumeIndices,
   363  	}
   364  	var reply proto.ReorderVmVolumesResponse
   365  	err := client.RequestReply("Hypervisor.ReorderVmVolumes", request, &reply)
   366  	if err != nil {
   367  		return err
   368  	}
   369  	return errors.New(reply.Error)
   370  }
   371  
   372  func scanVmRoot(client *srpc.Client, ipAddr net.IP,
   373  	scanFilter *filter.Filter) (*filesystem.FileSystem, error) {
   374  	request := proto.ScanVmRootRequest{IpAddress: ipAddr, Filter: scanFilter}
   375  	var reply proto.ScanVmRootResponse
   376  	err := client.RequestReply("Hypervisor.ScanVmRoot", request, &reply)
   377  	if err != nil {
   378  		return nil, err
   379  	}
   380  	return reply.FileSystem, errors.New(reply.Error)
   381  }
   382  
   383  func setDisabledState(client *srpc.Client, disable bool) error {
   384  	request := proto.SetDisabledStateRequest{Disable: disable}
   385  	var reply proto.SetDisabledStateResponse
   386  	err := client.RequestReply("Hypervisor.SetDisabledState", request, &reply)
   387  	if err != nil {
   388  		return err
   389  	}
   390  	return errors.New(reply.Error)
   391  }
   392  
   393  func startVm(client *srpc.Client, ipAddr net.IP, accessToken []byte) error {
   394  	request := proto.StartVmRequest{
   395  		AccessToken: accessToken,
   396  		IpAddress:   ipAddr,
   397  	}
   398  	var reply proto.StartVmResponse
   399  	err := client.RequestReply("Hypervisor.StartVm", request, &reply)
   400  	if err != nil {
   401  		return err
   402  	}
   403  	return errors.New(reply.Error)
   404  }
   405  
   406  func stopVm(client *srpc.Client, ipAddr net.IP, accessToken []byte) error {
   407  	request := proto.StopVmRequest{
   408  		AccessToken: accessToken,
   409  		IpAddress:   ipAddr,
   410  	}
   411  	var reply proto.StopVmResponse
   412  	err := client.RequestReply("Hypervisor.StopVm", request, &reply)
   413  	if err != nil {
   414  		return err
   415  	}
   416  	return errors.New(reply.Error)
   417  }