Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(430)

Delta Between Two Patch Sets: golxc.go

Issue 6852065: golxc: add first container tests (Closed)
Left Patch Set: golxc: add first container tests Created 11 years, 4 months ago
Right Patch Set: golxc: add first container tests Created 11 years, 4 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « export_test.go ('k') | golxc_test.go » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 // 1 //
2 // golxc - Go package to interact with Linux Containers (LXC). 2 // golxc - Go package to interact with Linux Containers (LXC).
3 // 3 //
4 // https://launchpad.net/golxc/ 4 // https://launchpad.net/golxc/
5 // 5 //
6 // Copyright (c) 2012 Canonical Ltd. 6 // Copyright (c) 2012 Canonical Ltd.
7 // 7 //
8 8
9 package golxc 9 package golxc
10 10
11 import ( 11 import (
12 "bytes"
13 "fmt" 12 "fmt"
14 "os" 13 "os"
15 "os/exec" 14 "os/exec"
16 "strconv" 15 "strconv"
17 "strings" 16 "strings"
18 ) 17 )
19 18
20 // Error reports the failure of a LXC command. 19 // Error reports the failure of a LXC command.
21 type Error struct { 20 type Error struct {
22 Name string 21 Name string
23 Err error 22 Err error
24 » StdErr string 23 » Output []string
25 } 24 }
26 25
27 func (e Error) Error() string { 26 func (e Error) Error() string {
28 » var info string 27 » if e.Output == nil {
29 » if strings.HasPrefix(e.StdErr, e.Name) { 28 » » return fmt.Sprintf("error executing %q: %v", e.Name, e.Err)
rog 2012/11/23 10:58:19 perhaps slightly more robust to do: HasPrefix(e.St
TheMue 2012/11/23 13:46:48 Done.
30 » » info = e.StdErr[len(e.Name)+2:] 29 » }
31 » } else { 30 » if len(e.Output) == 1 {
32 » » info = e.StdErr 31 » » return fmt.Sprintf("error executing %q: %v", e.Name, e.Output[0] )
33 » } 32 » }
34 » if info == "" { 33 » return fmt.Sprintf("error executing %q: %s", e.Name, strings.Join(e.Outp ut, "; "))
35 » » info = e.Err.Error()
36 » }
37 » return fmt.Sprintf("error executing %q: %s", e.Name, info)
38 } 34 }
39 35
40 // State represents a container state. 36 // State represents a container state.
41 type State string 37 type State string
42 38
43 const ( 39 const (
44 StateUnknown State = "UNKNOWN" 40 StateUnknown State = "UNKNOWN"
45 StateStopped State = "STOPPED" 41 StateStopped State = "STOPPED"
46 StateStarting State = "STARTING" 42 StateStarting State = "STARTING"
47 StateRunning State = "RUNNING" 43 StateRunning State = "RUNNING"
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
112 } 108 }
113 _, err := run("lxc-create", args...) 109 _, err := run("lxc-create", args...)
114 if err != nil { 110 if err != nil {
115 return err 111 return err
116 } 112 }
117 return nil 113 return nil
118 } 114 }
119 115
120 // Start runs the container as a daemon. 116 // Start runs the container as a daemon.
121 func (c *Container) Start(configFile, consoleFile string) error { 117 func (c *Container) Start(configFile, consoleFile string) error {
118 if !c.IsConstructed() {
119 return fmt.Errorf("container %q is not yet created", c.name)
120 }
122 args := []string{ 121 args := []string{
123 "--daemon", 122 "--daemon",
124 "-n", c.name, 123 "-n", c.name,
125 } 124 }
126 if configFile != "" { 125 if configFile != "" {
127 args = append(args, "-f", configFile) 126 args = append(args, "-f", configFile)
128 } 127 }
129 if consoleFile != "" { 128 if consoleFile != "" {
130 args = append(args, "-c", consoleFile) 129 args = append(args, "-c", consoleFile)
131 } 130 }
132 if c.LogFile != "" { 131 if c.LogFile != "" {
133 args = append(args, "-o", c.LogFile, "-l", string(c.LogLevel)) 132 args = append(args, "-o", c.LogFile, "-l", string(c.LogLevel))
134 } 133 }
135 _, err := run("lxc-start", args...) 134 _, err := run("lxc-start", args...)
136 if err != nil { 135 if err != nil {
137 return err 136 return err
138 } 137 }
139 return c.Wait(StateRunning) 138 return c.Wait(StateRunning)
140 } 139 }
141 140
142 // Stop terminates the running container. 141 // Stop terminates the running container.
143 func (c *Container) Stop() error { 142 func (c *Container) Stop() error {
143 if !c.IsConstructed() {
144 return fmt.Errorf("container %q is not yet created", c.name)
145 }
144 args := []string{ 146 args := []string{
145 "-n", c.name, 147 "-n", c.name,
146 } 148 }
147 if c.LogFile != "" { 149 if c.LogFile != "" {
148 args = append(args, "-o", c.LogFile, "-l", string(c.LogLevel)) 150 args = append(args, "-o", c.LogFile, "-l", string(c.LogLevel))
149 } 151 }
150 _, err := run("lxc-stop", args...) 152 _, err := run("lxc-stop", args...)
151 if err != nil { 153 if err != nil {
152 return err 154 return err
153 } 155 }
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after
297 return "/var/lib/lxc/" + c.name 299 return "/var/lib/lxc/" + c.name
298 } 300 }
299 301
300 // rootfs returns the name of the directory containing the 302 // rootfs returns the name of the directory containing the
301 // root filesystem of the container. 303 // root filesystem of the container.
302 func (c *Container) rootfs() string { 304 func (c *Container) rootfs() string {
303 return c.containerHome() + "/rootfs/" 305 return c.containerHome() + "/rootfs/"
304 } 306 }
305 307
306 // run executes the passed command and returns the output. 308 // run executes the passed command and returns the output.
307 func run(c string, args ...string) (string, error) { 309 func run(name string, args ...string) (string, error) {
308 » var outbuf bytes.Buffer 310 » cmd := exec.Command(name, args...)
309 » var errbuf bytes.Buffer 311 » output, err := cmd.CombinedOutput()
310 » cmd := exec.Command(c, args...) 312 » if err != nil {
311 » cmd.Stdout = &outbuf 313 » » return "", runError(name, err, output)
312 » cmd.Stderr = &errbuf 314 » }
313 » err := cmd.Run() 315 » return string(output), nil
314 » if err != nil { 316 }
315 » » return "", &Error{c, err, errbuf.String()} 317
316 » } 318 // runError creates an error if run fails.
317 » return outbuf.String(), nil 319 func runError(name string, err error, output []byte) error {
320 » e := &Error{name, err, nil}
321 » for _, l := range strings.Split(string(output), "\n") {
322 » » if strings.HasPrefix(l, name+": ") {
323 » » » l = l[len(name)+2:]
324 » » }
325 » » if l != "" {
326 » » » e.Output = append(e.Output, l)
327 » » }
328 » }
329 » return e
318 } 330 }
319 331
320 // keyValues retrieves key/value pairs out of a command output. 332 // keyValues retrieves key/value pairs out of a command output.
321 func keyValues(raw string, sep string) map[string]string { 333 func keyValues(raw string, sep string) map[string]string {
322 kv := map[string]string{} 334 kv := map[string]string{}
323 lines := strings.Split(raw, "\n") 335 lines := strings.Split(raw, "\n")
324 for _, line := range lines { 336 for _, line := range lines {
325 parts := strings.SplitN(line, sep, 2) 337 parts := strings.SplitN(line, sep, 2)
326 if len(parts) == 2 { 338 if len(parts) == 2 {
327 kv[parts[0]] = strings.TrimSpace(parts[1]) 339 kv[parts[0]] = strings.TrimSpace(parts[1])
(...skipping 11 matching lines...) Expand all
339 name := strings.TrimSpace(line) 351 name := strings.TrimSpace(line)
340 if name != "" { 352 if name != "" {
341 collector[name] = struct{}{} 353 collector[name] = struct{}{}
342 } 354 }
343 } 355 }
344 for name := range collector { 356 for name := range collector {
345 set = append(set, name) 357 set = append(set, name)
346 } 358 }
347 return set 359 return set
348 } 360 }
LEFTRIGHT

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b