Merge lp:~dave-cheney/pyjuju/go-command-jujut into lp:pyjuju/go

Proposed by Dave Cheney
Status: Rejected
Rejected by: Gustavo Niemeyer
Proposed branch: lp:~dave-cheney/pyjuju/go-command-jujut
Merge into: lp:pyjuju/go
Diff against target: 259 lines (+223/-0)
6 files modified
cmd/jujut/add_machine.go (+41/-0)
cmd/jujut/agent.go (+70/-0)
cmd/jujut/main.go (+16/-0)
cmd/jujut/remove_machine.go (+45/-0)
cmd/jujut/setup_dummy.go (+46/-0)
state/state.go (+5/-0)
To merge this branch: bzr merge lp:~dave-cheney/pyjuju/go-command-jujut
Reviewer Review Type Date Requested Status
Juju Engineering Pending
Review via email: mp+107902@code.launchpad.net

Description of the change

cmd: add jujut (juju testing)

jujut is a small tool I wrote to push values into the state
to test the provisioning agent. It doesn't replace unit tests
and is not intended to be shipped to customers.

It has value for me, and if accepted, I expect to be replaced at
some point when we have jujuc working.

https://codereview.appspot.com/6243070/

To post a comment you must log in.
Revision history for this message
William Reade (fwereade) wrote :

I'm -1 on this at the moment... it seems to have a fair amount of code
duplicated from elsewhere, and I really don't see what it gives us (that
couldn't/shouldn't be exercised by actual unit tests). A bit more
context might help me see the point...

http://codereview.appspot.com/6243070/

191. By Dave Cheney

merge from tip and fix

Revision history for this message
Gustavo Niemeyer (niemeyer) wrote :

I agree with William. Even without seeing his comments, we had already
debated about the low level of automated testing in the provisioning
agent. The use of this tool is a side effect of doing one-off tests
manually rather than introducing proper logic onto the tests that
continue to be run after it is integrated.

 From another perspective, some of these commands should be actual
commands of juju. add-machine and remove-machine are two great
candidates for living on the real command line suite.

https://codereview.appspot.com/6243070/

Unmerged revisions

191. By Dave Cheney

merge from tip and fix

190. By Dave Cheney

cmd: add jujut (juju testing)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory 'cmd/jujut'
2=== added file 'cmd/jujut/add_machine.go'
3--- cmd/jujut/add_machine.go 1970-01-01 00:00:00 +0000
4+++ cmd/jujut/add_machine.go 2012-06-01 06:46:20 +0000
5@@ -0,0 +1,41 @@
6+package main
7+
8+import (
9+ "launchpad.net/gnuflag"
10+ "launchpad.net/juju/go/cmd"
11+ "launchpad.net/juju/go/log"
12+ "launchpad.net/juju/go/state"
13+)
14+
15+func init() {
16+ jujut.Register(&AddMachineCommand{})
17+}
18+
19+type AddMachineCommand struct {
20+ Conf AgentConf
21+}
22+
23+// Info returns usage information for the command.
24+func (a *AddMachineCommand) Info() *cmd.Info {
25+ return &cmd.Info{"add-machine", "", "add a machine", ""}
26+}
27+
28+// Init initializes the command for running.
29+func (a *AddMachineCommand) Init(f *gnuflag.FlagSet, args []string) error {
30+ a.Conf.addFlags(f)
31+ if err := f.Parse(true, args); err != nil {
32+ return err
33+ }
34+ return a.Conf.checkArgs(f.Args())
35+}
36+
37+func (a *AddMachineCommand) Run(_ *cmd.Context) error {
38+ st, err := state.Open(&a.Conf.StateInfo)
39+ if err != nil {
40+ return err
41+ }
42+
43+ m, err := st.AddMachine()
44+ log.Printf("added machine: %v", m)
45+ return err
46+}
47
48=== added file 'cmd/jujut/agent.go'
49--- cmd/jujut/agent.go 1970-01-01 00:00:00 +0000
50+++ cmd/jujut/agent.go 2012-06-01 06:46:20 +0000
51@@ -0,0 +1,70 @@
52+package main
53+
54+import (
55+ "fmt"
56+ "launchpad.net/gnuflag"
57+ "launchpad.net/juju/go/cmd"
58+ "launchpad.net/juju/go/state"
59+ "regexp"
60+ "strings"
61+)
62+
63+// requiredError is useful when complaining about missing command-line options.
64+func requiredError(name string) error {
65+ return fmt.Errorf("--%s option must be set", name)
66+}
67+
68+// stateInfoValue implements gnuflag.Value on a state.Info.
69+type stateInfoValue state.Info
70+
71+var validAddr = regexp.MustCompile("^.+:[0-9]+$")
72+
73+// Set splits the comma-separated list of ZooKeeper addresses and stores
74+// onto v's Addrs. Addresses must include port numbers.
75+func (v *stateInfoValue) Set(value string) error {
76+ addrs := strings.Split(value, ",")
77+ for _, addr := range addrs {
78+ if !validAddr.MatchString(addr) {
79+ return fmt.Errorf("%q is not a valid zookeeper address", addr)
80+ }
81+ }
82+ v.Addrs = addrs
83+ return nil
84+}
85+
86+// String returns the list of ZooKeeper addresses joined by commas.
87+func (v *stateInfoValue) String() string {
88+ if v.Addrs != nil {
89+ return strings.Join(v.Addrs, ",")
90+ }
91+ return ""
92+}
93+
94+// stateInfoVar sets up a gnuflag flag analagously to FlagSet.*Var methods.
95+func stateInfoVar(fs *gnuflag.FlagSet, target *state.Info, name string, value []string, usage string) {
96+ target.Addrs = value
97+ fs.Var((*stateInfoValue)(target), name, usage)
98+}
99+
100+// AgentConf handles command-line flags shared by all agents.
101+type AgentConf struct {
102+ JujuDir string // Defaults to "/var/lib/juju".
103+ StateInfo state.Info
104+}
105+
106+// addFlags injects common agent flags into f.
107+func (c *AgentConf) addFlags(f *gnuflag.FlagSet) {
108+ f.StringVar(&c.JujuDir, "juju-directory", "/var/lib/juju", "juju working directory")
109+ stateInfoVar(f, &c.StateInfo, "zookeeper-servers", nil, "zookeeper servers to connect to")
110+}
111+
112+// checkArgs checks that required flags have been set and that args is empty.
113+func (c *AgentConf) checkArgs(args []string) error {
114+ if c.JujuDir == "" {
115+ return requiredError("juju-directory")
116+ }
117+ if c.StateInfo.Addrs == nil {
118+ return requiredError("zookeeper-servers")
119+ }
120+ return cmd.CheckEmpty(args)
121+}
122
123=== added file 'cmd/jujut/main.go'
124--- cmd/jujut/main.go 1970-01-01 00:00:00 +0000
125+++ cmd/jujut/main.go 2012-06-01 06:46:20 +0000
126@@ -0,0 +1,16 @@
127+package main
128+
129+import (
130+ "launchpad.net/juju/go/cmd"
131+ "os"
132+)
133+
134+var jujut = &cmd.SuperCommand{Name: "jujut", Doc: "", Log: &cmd.Log{}}
135+
136+func Main(args []string) {
137+ os.Exit(cmd.Main(jujut, cmd.DefaultContext(), args[1:]))
138+}
139+
140+func main() {
141+ Main(os.Args)
142+}
143
144=== added file 'cmd/jujut/remove_machine.go'
145--- cmd/jujut/remove_machine.go 1970-01-01 00:00:00 +0000
146+++ cmd/jujut/remove_machine.go 2012-06-01 06:46:20 +0000
147@@ -0,0 +1,45 @@
148+package main
149+
150+import (
151+ "fmt"
152+
153+ "launchpad.net/gnuflag"
154+ "launchpad.net/juju/go/cmd"
155+ "launchpad.net/juju/go/state"
156+)
157+
158+func init() {
159+ jujut.Register(&RemoveMachineCommand{})
160+}
161+
162+type RemoveMachineCommand struct {
163+ Conf AgentConf
164+ MachineId int
165+}
166+
167+// Info returns usage information for the command.
168+func (a *RemoveMachineCommand) Info() *cmd.Info {
169+ return &cmd.Info{"remove-machine", "", "remove a machine", ""}
170+}
171+
172+// Init initializes the command for running.
173+func (a *RemoveMachineCommand) Init(f *gnuflag.FlagSet, args []string) error {
174+ a.Conf.addFlags(f)
175+ f.IntVar(&a.MachineId, "machine-id", -1, "id of the machine to run")
176+ if err := f.Parse(true, args); err != nil {
177+ return err
178+ }
179+ if a.MachineId < 0 {
180+ return fmt.Errorf("--machine-id option must be set, and expects a non-negative integer")
181+ }
182+ return a.Conf.checkArgs(f.Args())
183+}
184+
185+func (a *RemoveMachineCommand) Run(_ *cmd.Context) error {
186+ st, err := state.Open(&a.Conf.StateInfo)
187+ if err != nil {
188+ return err
189+ }
190+ err = st.RemoveMachine(a.MachineId)
191+ return err
192+}
193
194=== added file 'cmd/jujut/setup_dummy.go'
195--- cmd/jujut/setup_dummy.go 1970-01-01 00:00:00 +0000
196+++ cmd/jujut/setup_dummy.go 2012-06-01 06:46:20 +0000
197@@ -0,0 +1,46 @@
198+package main
199+
200+import (
201+ "launchpad.net/gnuflag"
202+ "launchpad.net/juju/go/cmd"
203+ "launchpad.net/juju/go/state"
204+)
205+
206+func init() {
207+ jujut.Register(&SetupDummyCommand{})
208+}
209+
210+type SetupDummyCommand struct {
211+ Conf AgentConf
212+}
213+
214+// Info returns usage information for the command.
215+func (a *SetupDummyCommand) Info() *cmd.Info {
216+ return &cmd.Info{"setup-dummy", "", "setup dummy environment in the local zk", ""}
217+}
218+
219+// Init initializes the command for running.
220+func (a *SetupDummyCommand) Init(f *gnuflag.FlagSet, args []string) error {
221+ a.Conf.addFlags(f)
222+ if err := f.Parse(true, args); err != nil {
223+ return err
224+ }
225+ return a.Conf.checkArgs(f.Args())
226+}
227+
228+func (a *SetupDummyCommand) Run(_ *cmd.Context) error {
229+ st, err := state.Open(&a.Conf.StateInfo)
230+ if err != nil {
231+ return err
232+ }
233+
234+ env, err := st.Environment()
235+ if err != nil {
236+ return err
237+ }
238+ env.Set("type", "dummy")
239+ env.Set("zookeeper", false)
240+ env.Set("name", "testing")
241+ _, err = env.Write()
242+ return err
243+}
244
245=== modified file 'state/state.go'
246--- state/state.go 2012-05-29 23:11:41 +0000
247+++ state/state.go 2012-06-01 06:46:20 +0000
248@@ -74,6 +74,11 @@
249 return newConfigWatcher(s, zkEnvironmentPath)
250 }
251
252+// Environment returns the current environment configuration.
253+func (s *State) Environment() (*ConfigNode, error) {
254+ return readConfigNode(s.zk, zkEnvironmentPath)
255+}
256+
257 // Machine returns the machine with the given id.
258 func (s *State) Machine(id int) (*Machine, error) {
259 key := machineKey(id)

Subscribers

People subscribed via source and target branches

to all changes: