github.com/mattyw/juju@v0.0.0-20140610034352-732aecd63861/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 string, arch string) error {
    44  	args := []string{
    45  		"sync",
    46  		fmt.Sprintf("arch=%s", arch),
    47  		fmt.Sprintf("release=%s", series),
    48  	}
    49  	_, err := run("uvt-simplestreams-libvirt", args...)
    50  	return err
    51  }
    52  
    53  type CreateMachineParams struct {
    54  	Hostname      string
    55  	Series        string
    56  	Arch          string
    57  	UserDataFile  string
    58  	NetworkBridge string
    59  	Memory        uint64
    60  	CpuCores      uint64
    61  	RootDisk      uint64
    62  }
    63  
    64  // CreateMachine creates a virtual machine and starts it.
    65  func CreateMachine(params CreateMachineParams) error {
    66  	if params.Hostname == "" {
    67  		return fmt.Errorf("Hostname is required")
    68  	}
    69  	args := []string{
    70  		"create",
    71  		"--log-console-output", // do wonder where this goes...
    72  	}
    73  	if params.UserDataFile != "" {
    74  		args = append(args, "--user-data", params.UserDataFile)
    75  	}
    76  	if params.NetworkBridge != "" {
    77  		args = append(args, "--bridge", params.NetworkBridge)
    78  	}
    79  	if params.Memory != 0 {
    80  		args = append(args, "--memory", fmt.Sprint(params.Memory))
    81  	}
    82  	if params.CpuCores != 0 {
    83  		args = append(args, "--cpu", fmt.Sprint(params.CpuCores))
    84  	}
    85  	if params.RootDisk != 0 {
    86  		args = append(args, "--disk", fmt.Sprint(params.RootDisk))
    87  	}
    88  	// TODO add memory, cpu and disk prior to hostname
    89  	args = append(args, params.Hostname)
    90  	if params.Series != "" {
    91  		args = append(args, fmt.Sprintf("release=%s", params.Series))
    92  	}
    93  	if params.Arch != "" {
    94  		args = append(args, fmt.Sprintf("arch=%s", params.Arch))
    95  	}
    96  	output, err := run("uvt-kvm", args...)
    97  	logger.Debugf("is this the logged output?:\n%s", output)
    98  	return err
    99  }
   100  
   101  // DestroyMachine destroys the virtual machine identified by hostname.
   102  func DestroyMachine(hostname string) error {
   103  	_, err := run("uvt-kvm", "destroy", hostname)
   104  	return err
   105  }
   106  
   107  // AutostartMachine indicates that the virtual machines should automatically
   108  // restart when the host restarts.
   109  func AutostartMachine(hostname string) error {
   110  	_, err := run("virsh", "autostart", hostname)
   111  	return err
   112  }
   113  
   114  // ListMachines returns a map of machine name to state, where state is one of:
   115  // running, idle, paused, shutdown, shut off, crashed, dying, pmsuspended.
   116  func ListMachines() (map[string]string, error) {
   117  	output, err := run("virsh", "-q", "list", "--all")
   118  	if err != nil {
   119  		return nil, err
   120  	}
   121  	// Split the output into lines.
   122  	// Regex matching is the easiest way to match the lines.
   123  	//   id hostname status
   124  	// separated by whitespace, with whitespace at the start too.
   125  	result := make(map[string]string)
   126  	for _, s := range machineListPattern.FindAllStringSubmatchIndex(output, -1) {
   127  		hostnameAndStatus := machineListPattern.ExpandString(nil, "$hostname $status", output, s)
   128  		parts := strings.SplitN(string(hostnameAndStatus), " ", 2)
   129  		result[parts[0]] = parts[1]
   130  	}
   131  	return result, nil
   132  }