github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/container/kvm/libvirt.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package kvm
     5  
     6  // This file contains wrappers around the following executables:
     7  //   uvt-simplestreams-libvirt
     8  //   uvt-kvm
     9  //   virsh
    10  // Those executables are found in the following packages:
    11  //   uvtool-libvirt
    12  //   libvirt-bin
    13  //
    14  // These executables provide Juju's interface to dealing with kvm containers.
    15  // The define how we start, stop and list running containers on the host
    16  
    17  import (
    18  	"fmt"
    19  	"regexp"
    20  	"strings"
    21  
    22  	"github.com/juju/utils"
    23  )
    24  
    25  var (
    26  	// The regular expression for breaking up the results of 'virsh list'
    27  	// (?m) - specify that this is a multiline regex
    28  	// first part is the opaque identifier we don't care about
    29  	// then the hostname, and lastly the status.
    30  	machineListPattern = regexp.MustCompile(`(?m)^\s+\d+\s+(?P<hostname>[-\w]+)\s+(?P<status>.+)\s*$`)
    31  )
    32  
    33  // run the command and return the combined output.
    34  func run(command string, args ...string) (output string, err error) {
    35  	logger.Tracef("%s %v", command, args)
    36  	output, err = utils.RunCommand(command, args...)
    37  	logger.Tracef("output: %v", output)
    38  	return output, err
    39  }
    40  
    41  // SyncImages updates the local cached images by reading the simplestreams
    42  // data and downloading the cloud images to the uvtool pool (used by libvirt).
    43  func SyncImages(series, arch, source string) error {
    44  
    45  	args := []string{
    46  		"sync",
    47  		fmt.Sprintf("arch=%s", arch),
    48  		fmt.Sprintf("release=%s", series),
    49  	}
    50  
    51  	if source != "" {
    52  		args = append(args, fmt.Sprintf("--source=%s", source))
    53  	}
    54  
    55  	_, err := run("uvt-simplestreams-libvirt", args...)
    56  	return err
    57  }
    58  
    59  type CreateMachineParams struct {
    60  	Hostname      string
    61  	Series        string
    62  	Arch          string
    63  	UserDataFile  string
    64  	NetworkBridge string
    65  	Memory        uint64
    66  	CpuCores      uint64
    67  	RootDisk      uint64
    68  }
    69  
    70  // CreateMachine creates a virtual machine and starts it.
    71  func CreateMachine(params CreateMachineParams) error {
    72  	if params.Hostname == "" {
    73  		return fmt.Errorf("Hostname is required")
    74  	}
    75  	args := []string{
    76  		"create",
    77  		"--log-console-output", // do wonder where this goes...
    78  	}
    79  	if params.UserDataFile != "" {
    80  		args = append(args, "--user-data", params.UserDataFile)
    81  	}
    82  	if params.NetworkBridge != "" {
    83  		args = append(args, "--bridge", params.NetworkBridge)
    84  	}
    85  	if params.Memory != 0 {
    86  		args = append(args, "--memory", fmt.Sprint(params.Memory))
    87  	}
    88  	if params.CpuCores != 0 {
    89  		args = append(args, "--cpu", fmt.Sprint(params.CpuCores))
    90  	}
    91  	if params.RootDisk != 0 {
    92  		args = append(args, "--disk", fmt.Sprint(params.RootDisk))
    93  	}
    94  	// TODO add memory, cpu and disk prior to hostname
    95  	args = append(args, params.Hostname)
    96  	if params.Series != "" {
    97  		args = append(args, fmt.Sprintf("release=%s", params.Series))
    98  	}
    99  	if params.Arch != "" {
   100  		args = append(args, fmt.Sprintf("arch=%s", params.Arch))
   101  	}
   102  	output, err := run("uvt-kvm", args...)
   103  	logger.Debugf("is this the logged output?:\n%s", output)
   104  	return err
   105  }
   106  
   107  // DestroyMachine destroys the virtual machine identified by hostname.
   108  func DestroyMachine(hostname string) error {
   109  	_, err := run("uvt-kvm", "destroy", hostname)
   110  	return err
   111  }
   112  
   113  // AutostartMachine indicates that the virtual machines should automatically
   114  // restart when the host restarts.
   115  func AutostartMachine(hostname string) error {
   116  	_, err := run("virsh", "autostart", hostname)
   117  	return err
   118  }
   119  
   120  // ListMachines returns a map of machine name to state, where state is one of:
   121  // running, idle, paused, shutdown, shut off, crashed, dying, pmsuspended.
   122  func ListMachines() (map[string]string, error) {
   123  	output, err := run("virsh", "-q", "list", "--all")
   124  	if err != nil {
   125  		return nil, err
   126  	}
   127  	// Split the output into lines.
   128  	// Regex matching is the easiest way to match the lines.
   129  	//   id hostname status
   130  	// separated by whitespace, with whitespace at the start too.
   131  	result := make(map[string]string)
   132  	for _, s := range machineListPattern.FindAllStringSubmatchIndex(output, -1) {
   133  		hostnameAndStatus := machineListPattern.ExpandString(nil, "$hostname $status", output, s)
   134  		parts := strings.SplitN(string(hostnameAndStatus), " ", 2)
   135  		result[parts[0]] = parts[1]
   136  	}
   137  	return result, nil
   138  }