github.com/cloud-foundations/dominator@v0.0.0-20221004181915-6e4fee580046/cmd/vm-control/exportLocalVm.go (about)

     1  package main
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"os"
     7  	"os/exec"
     8  
     9  	hyperclient "github.com/Cloud-Foundations/Dominator/hypervisor/client"
    10  	"github.com/Cloud-Foundations/Dominator/lib/errors"
    11  	"github.com/Cloud-Foundations/Dominator/lib/json"
    12  	"github.com/Cloud-Foundations/Dominator/lib/log"
    13  	"github.com/Cloud-Foundations/Dominator/lib/srpc"
    14  	proto "github.com/Cloud-Foundations/Dominator/proto/hypervisor"
    15  )
    16  
    17  type vmExporter interface {
    18  	createVm(hostname string, vmInfo proto.ExportLocalVmInfo) error
    19  	destroyVm(hostname string) error
    20  }
    21  
    22  type vmExporterExec struct {
    23  	createCommand  string
    24  	destroyCommand string
    25  }
    26  
    27  func exportLocalVmSubcommand(args []string, logger log.DebugLogger) error {
    28  	if err := exportLocalVm(args[0], logger); err != nil {
    29  		return fmt.Errorf("Error exporting VM: %s", err)
    30  	}
    31  	return nil
    32  }
    33  
    34  func exportLocalVm(vmHostname string, logger log.DebugLogger) error {
    35  	return vmExport(vmHostname, vmExporterExec{*localVmCreate, *localVmDestroy},
    36  		logger)
    37  }
    38  
    39  func (exporter vmExporterExec) createVm(hostname string,
    40  	vmInfo proto.ExportLocalVmInfo) error {
    41  	if exporter.createCommand == "" {
    42  		if err := json.WriteWithIndent(os.Stdout, "    ", vmInfo); err != nil {
    43  			return err
    44  		}
    45  		return errors.New("no command specified: debug mode")
    46  	}
    47  	buffer := &bytes.Buffer{}
    48  	if err := json.WriteWithIndent(buffer, "    ", vmInfo); err != nil {
    49  		return err
    50  	}
    51  	cmd := exec.Command(exporter.createCommand, hostname)
    52  	cmd.Stdin = buffer
    53  	cmd.Stdout = os.Stdout
    54  	cmd.Stderr = os.Stderr
    55  	return cmd.Run()
    56  }
    57  
    58  func (exporter vmExporterExec) destroyVm(hostname string) error {
    59  	cmd := exec.Command(exporter.destroyCommand, hostname)
    60  	cmd.Stdout = os.Stdout
    61  	cmd.Stderr = os.Stderr
    62  	return cmd.Run()
    63  }
    64  
    65  func vmExport(vmHostname string, exporter vmExporter,
    66  	logger log.DebugLogger) error {
    67  	vmIpAddr, err := lookupIP(vmHostname)
    68  	if err != nil {
    69  		return err
    70  	}
    71  	hypervisor := fmt.Sprintf(":%d", *hypervisorPortNum)
    72  	client, err := srpc.DialHTTP("tcp", hypervisor, 0)
    73  	if err != nil {
    74  		return err
    75  	}
    76  	defer client.Close()
    77  	rootCookie, err := readRootCookie(client, logger)
    78  	if err != nil {
    79  		return err
    80  	}
    81  	if err := hyperclient.StopVm(client, vmIpAddr, nil); err != nil {
    82  		return err
    83  	}
    84  	doStart := true
    85  	defer func() {
    86  		if doStart {
    87  			if err := hyperclient.StartVm(client, vmIpAddr, nil); err != nil {
    88  				logger.Println(err)
    89  			}
    90  		}
    91  	}()
    92  	vmInfo, err := hyperclient.ExportLocalVm(client, vmIpAddr, rootCookie)
    93  	if err != nil {
    94  		return err
    95  	}
    96  	if err := exporter.createVm(vmHostname, vmInfo); err != nil {
    97  		return err
    98  	}
    99  	response, err := askForInputChoice("Commit VM "+vmIpAddr.String(),
   100  		[]string{"commit", "defer", "abandon"})
   101  	if err != nil {
   102  		return err
   103  	}
   104  	switch response {
   105  	case "abandon":
   106  		if err := exporter.destroyVm(vmHostname); err != nil {
   107  			return err
   108  		}
   109  		return errorCommitAbandoned
   110  	case "commit":
   111  		if err := hyperclient.DestroyVm(client, vmIpAddr, nil); err != nil {
   112  			return err
   113  		}
   114  		doStart = false
   115  		return nil
   116  	case "defer":
   117  		doStart = false
   118  		return errorCommitDeferred
   119  	}
   120  	return fmt.Errorf("invalid response: %s", response)
   121  }