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 }