github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/acceptancetests/repository/charms/fill-logs/actions/actions.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "io" 6 "os" 7 "os/exec" 8 "path/filepath" 9 "strconv" 10 "strings" 11 ) 12 13 func main() { 14 if err := run(os.Args); err != nil { 15 fmt.Fprintln(os.Stderr, err) 16 os.Exit(1) 17 } 18 } 19 20 func run(args []string) error { 21 if len(args) != 2 { 22 return fmt.Errorf("expected exactly one argument, the action name") 23 } 24 switch args[1] { 25 case "fill-unit": 26 return fillUnit() 27 case "fill-machine": 28 return fillMachine() 29 case "unit-size": 30 return unitLogSizes() 31 case "machine-size": 32 return machineLogSizes() 33 default: 34 return fmt.Errorf("unknown action: %q", args[1]) 35 } 36 } 37 38 func fillUnit() error { 39 return fillLog(os.Stdout) 40 } 41 42 func unitLogSizes() error { 43 return writeSizes("/var/log/juju/unit-fill-logs*.log*") 44 } 45 46 func machineLogSizes() error { 47 return writeSizes("/var/log/juju/machine-*.log*") 48 } 49 50 func fillMachine() (err error) { 51 machine, err := getMachine() 52 if err != nil { 53 return err 54 } 55 svcname := fmt.Sprintf("jujud-machine-%d", machine) 56 out, err := exec.Command("service", svcname, "stop").CombinedOutput() 57 if err != nil { 58 return fmt.Errorf("error stopping machine agent %q: %s", svcname, out) 59 } 60 defer func() { 61 out, err2 := exec.Command("service", svcname, "start").CombinedOutput() 62 if err2 == nil { 63 return 64 } 65 if err == nil { 66 // function error is currently nil, so overwrite with this one. 67 err = fmt.Errorf("error starting machine agent %q: %s", svcname, out) 68 return 69 } 70 // function error is non-nil, so can't overwrite, just print. 71 fmt.Printf("error starting machine agent %q: %s", svcname, out) 72 }() 73 logname := fmt.Sprintf("/var/log/juju/machine-%d.log", machine) 74 f, err := os.OpenFile(logname, os.O_APPEND|os.O_WRONLY, 0644) 75 if err != nil { 76 return fmt.Errorf("failed to open machine log file: %v", err) 77 } 78 defer f.Close() 79 return fillLog(f) 80 } 81 82 func fillLog(w io.Writer) error { 83 megs, err := getMegs() 84 if err != nil { 85 return err 86 } 87 bytes := megs * 1024 * 1024 88 total := 0 89 90 for total < bytes { 91 // technically, the log file will be bigger than asked for, since it 92 // prepends a bunch of stuff to each log call, but this guarantees we've 93 // put *at least* this much data in the log, which should guarantee a 94 // rotation. 95 n, err := fmt.Fprintln(w, lorem) 96 if err != nil { 97 return fmt.Errorf("error writing to log: %s", err) 98 } 99 total += n 100 } 101 return nil 102 } 103 104 func writeSizes(glob string) error { 105 paths, err := filepath.Glob(glob) 106 if err != nil { 107 return fmt.Errorf("error getting logs for %q: %s", glob, err) 108 } 109 110 // go through the list in reverse, since the primary log file is always last, 111 // but it's a lot more convenient for parsing if it's first in the output. 112 for i, j := len(paths)-1, 0; i >= 0; i-- { 113 path := paths[i] 114 // Skip any log files that start with machine-lock as these aren't interesting 115 // for fill logs. 116 if strings.HasPrefix(filepath.Base(path), "machine-lock") { 117 continue 118 } 119 info, err := os.Stat(path) 120 if err != nil { 121 return fmt.Errorf("error stating log %q: %s", path, err) 122 } 123 name := fmt.Sprintf("result-map.log%d.name=%s", j, path) 124 size := fmt.Sprintf("result-map.log%d.size=%d", j, info.Size()/1024/1024) 125 out, err := exec.Command("action-set", name, size).CombinedOutput() 126 if err != nil { 127 return fmt.Errorf("error calling action-set: %s", out) 128 } 129 j++ 130 } 131 132 return nil 133 } 134 135 func getMegs() (int, error) { 136 return getInt("megs") 137 } 138 139 func getMachine() (int, error) { 140 return getInt("machine") 141 } 142 143 func getInt(name string) (int, error) { 144 out, err := exec.Command("action-get", name).CombinedOutput() 145 if err != nil { 146 fmt.Fprintln(os.Stderr, out) 147 return 0, fmt.Errorf("error calling action-get: %s", err) 148 } 149 // for some reason the output always comes with a /n at the end, so just 150 // trim it. 151 return strconv.Atoi(strings.TrimSpace(string(out))) 152 } 153 154 const lorem = `Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.`