~rogpeppe/juju-core/trunk

« back to all changes in this revision

Viewing changes to cmd/juju-wait/main.go

  • Committer: Roger Peppe
  • Date: 2013-04-12 14:42:22 UTC
  • Revision ID: roger.peppe@canonical.com-20130412144222-g8zu20ed7esun45d
cmd/juju-wait: new command

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
package main
 
2
 
 
3
import (
 
4
        "flag"
 
5
        "fmt"
 
6
        stdlog "log"
 
7
        "os"
 
8
        "regexp"
 
9
 
 
10
        "launchpad.net/juju-core/environs"
 
11
        _ "launchpad.net/juju-core/environs/ec2"
 
12
        "launchpad.net/juju-core/juju"
 
13
        "launchpad.net/juju-core/log"
 
14
        "launchpad.net/juju-core/state/api"
 
15
        "launchpad.net/juju-core/state/api/params"
 
16
)
 
17
 
 
18
var help = `
 
19
juju-wait waits for the unit with the given name to reach a status
 
20
matching the given anchored regular expression.  The pattern matches
 
21
against the status code followed by a space and the status information
 
22
if there is some status information.
 
23
 
 
24
For example, a unit that encountered an error running the install hook
 
25
would match the regular expression 'error hook failed: "install"'.
 
26
 
 
27
If the unit is removed, the status is 'removed'.
 
28
 
 
29
Juju-wait returns a non-zero exit status if there is an error connecting
 
30
to the juju environment, if the unit does not exist when juju-wait starts,
 
31
or if the unit is removed and the pattern does not match "removed".
 
32
`
 
33
 
 
34
var envName = flag.String("e", "", "environment name")
 
35
var verbose = flag.Bool("v", false, "print non-matching states to standard error as they are seen")
 
36
var debug = flag.Bool("debug", false, "print debugging messages to standard error")
 
37
 
 
38
func main() {
 
39
        flag.Usage = func() {
 
40
                fmt.Fprintf(os.Stderr, "usage: juju-wait [flags] unit-name regexp\n")
 
41
                flag.PrintDefaults()
 
42
                fmt.Fprintf(os.Stderr, "%s", help)
 
43
                os.Exit(2)
 
44
        }
 
45
        flag.Parse()
 
46
        if flag.NArg() != 2 {
 
47
                flag.Usage()
 
48
        }
 
49
        unitName := flag.Arg(0)
 
50
        statusPattern, err := regexp.Compile("^" + flag.Arg(1) + "$")
 
51
        if err != nil {
 
52
                fatalf("invalid status regular expression: %v", err)
 
53
        }
 
54
        if *debug {
 
55
                log.SetTarget(stdlog.New(os.Stderr, "", stdlog.LstdFlags))
 
56
        }
 
57
        if err := juju.InitJujuHome(); err != nil {
 
58
                fatalf("cannot initialise juju home: %v", err)
 
59
        }
 
60
        client, err := openAPIClient(*envName)
 
61
        if err != nil {
 
62
                fatalf("cannot open API: %v", err)
 
63
        }
 
64
        w, err := client.WatchAll()
 
65
        if err != nil {
 
66
                fatalf("cannot watch all: %v", err)
 
67
        }
 
68
        defer w.Stop()
 
69
        unit, err := wait(unitName, statusPattern, w)
 
70
        if err != nil {
 
71
                fatalf("%v", err)
 
72
        }
 
73
        fmt.Printf("%s\n", status(unit))
 
74
}
 
75
 
 
76
type watcher interface {
 
77
        Next() ([]params.Delta, error)
 
78
}
 
79
 
 
80
func wait(unitName string, statusPattern *regexp.Regexp, w watcher) (*params.UnitInfo, error) {
 
81
        var unit *params.UnitInfo
 
82
        for {
 
83
                deltas, err := w.Next()
 
84
                if err != nil {
 
85
                        return nil, fmt.Errorf("cannot get next deltas: %v", err)
 
86
                }
 
87
                var found *params.UnitInfo
 
88
                var removed bool
 
89
                for _, d := range deltas {
 
90
                        if u, ok := d.Entity.(*params.UnitInfo); ok && u.Name == unitName {
 
91
                                found = u
 
92
                                removed = d.Removed
 
93
                        }
 
94
                }
 
95
                if found == nil {
 
96
                        // The first set of deltas should contain information about
 
97
                        // all entities in the environment.
 
98
                        if unit == nil {
 
99
                                return nil, fmt.Errorf("unit %q does not exist", unitName)
 
100
                        }
 
101
                        continue
 
102
                }
 
103
                unit = found
 
104
                if removed {
 
105
                        unit.Status, unit.StatusInfo = "removed", ""
 
106
                }
 
107
                if statusPattern.MatchString(status(unit)) {
 
108
                        break
 
109
                }
 
110
                if *verbose {
 
111
                        fmt.Fprintf(os.Stderr, "%s\n", status(unit))
 
112
                }
 
113
                if removed {
 
114
                        return nil, fmt.Errorf("unit was removed")
 
115
                }
 
116
        }
 
117
        return unit, nil
 
118
}
 
119
 
 
120
func status(unit *params.UnitInfo) string {
 
121
        s := string(unit.Status)
 
122
        if unit.StatusInfo != "" {
 
123
                s += " " + unit.StatusInfo
 
124
        }
 
125
        return s
 
126
}
 
127
 
 
128
func openAPIClient(envName string) (*api.Client, error) {
 
129
        env, err := environs.NewFromName("")
 
130
        if err != nil {
 
131
                return nil, fmt.Errorf("cannot open environ: %v", err)
 
132
        }
 
133
        _, info, err := env.StateInfo()
 
134
        if err != nil {
 
135
                return nil, fmt.Errorf("cannot get api info: %v", err)
 
136
        }
 
137
        info.Tag = "user-admin"
 
138
        info.Password = env.Config().AdminSecret()
 
139
        st, err := api.Open(info)
 
140
        if err != nil {
 
141
                return nil, fmt.Errorf("cannot open api: %v", err)
 
142
        }
 
143
 
 
144
        return st.Client(), nil
 
145
}
 
146
 
 
147
func fatalf(f string, args ...interface{}) {
 
148
        fmt.Fprintf(os.Stderr, "juju-wait: %s\n", fmt.Sprintf(f, args...))
 
149
        os.Exit(2)
 
150
}