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 }