Merge lp:~mattyw/juju-core/user-add-remove-cli into lp:~go-bot/juju-core/trunk
- user-add-remove-cli
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Matthew Williams |
Approved revision: | no longer in the source branch. |
Merged at revision: | 2527 |
Proposed branch: | lp:~mattyw/juju-core/user-add-remove-cli |
Merge into: | lp:~go-bot/juju-core/trunk |
Diff against target: |
2254 lines (+646/-128) 63 files modified
cmd/cmd.go (+7/-7) cmd/envcmd/environmentcommand.go (+15/-2) cmd/envcmd/environmentcommand_test.go (+21/-18) cmd/envcmd/export_test.go (+1/-1) cmd/juju/addmachine.go (+6/-1) cmd/juju/addrelation.go (+6/-1) cmd/juju/addunit.go (+2/-1) cmd/juju/adduser.go (+103/-0) cmd/juju/adduser_test.go (+106/-0) cmd/juju/authorisedkeys_add.go (+6/-1) cmd/juju/authorisedkeys_delete.go (+6/-1) cmd/juju/authorisedkeys_import.go (+6/-1) cmd/juju/authorisedkeys_list.go (+10/-1) cmd/juju/bootstrap.go (+6/-1) cmd/juju/bootstrap_test.go (+2/-5) cmd/juju/cmd_test.go (+2/-1) cmd/juju/constraints.go (+11/-2) cmd/juju/debuglog_test.go (+2/-2) cmd/juju/deploy.go (+6/-1) cmd/juju/destroymachine.go (+6/-1) cmd/juju/destroyrelation.go (+6/-1) cmd/juju/destroyservice.go (+6/-1) cmd/juju/destroyunit.go (+6/-1) cmd/juju/endpoint.go (+6/-1) cmd/juju/ensureavailability.go (+6/-1) cmd/juju/environment.go (+16/-3) cmd/juju/expose.go (+6/-1) cmd/juju/get.go (+6/-1) cmd/juju/plugin.go (+3/-2) cmd/juju/publish.go (+6/-1) cmd/juju/publish_test.go (+3/-5) cmd/juju/removeuser.go (+55/-0) cmd/juju/removeuser_test.go (+35/-0) cmd/juju/resolved.go (+6/-1) cmd/juju/retryprovisioning.go (+2/-1) cmd/juju/run.go (+6/-1) cmd/juju/run_test.go (+1/-1) cmd/juju/set.go (+6/-1) cmd/juju/ssh.go (+6/-1) cmd/juju/status.go (+3/-2) cmd/juju/switch.go (+3/-2) cmd/juju/switch_test.go (+2/-2) cmd/juju/synctools.go (+6/-1) cmd/juju/unexpose.go (+6/-1) cmd/juju/unset.go (+6/-1) cmd/juju/upgradecharm.go (+6/-1) cmd/juju/upgradejuju.go (+6/-1) cmd/jujud/run_test.go (+3/-3) cmd/plugins/juju-metadata/imagemetadata.go (+2/-1) cmd/plugins/juju-metadata/toolsmetadata.go (+10/-1) cmd/plugins/juju-metadata/validateimagemetadata.go (+7/-2) cmd/plugins/juju-metadata/validatetoolsmetadata.go (+7/-2) cmd/plugins/juju-restore/restore.go (+6/-1) cmd/supercommand.go (+0/-1) environs/configstore/disk.go (+23/-18) environs/configstore/mem.go (+2/-2) environs/manual/init_test.go (+3/-3) environs/manual/provisioner_test.go (+2/-2) juju/api.go (+9/-0) state/api/params/params.go (+6/-0) state/apiserver/client/api_test.go (+1/-1) state/user_test.go (+6/-6) testing/environ.go (+4/-2) |
To merge this branch: | bzr merge lp:~mattyw/juju-core/user-add-remove-cli |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Juju Engineering | Pending | ||
Review via email: mp+210962@code.launchpad.net |
Commit message
https:/
Preliminary support for basic juju id commands:
juju add-user <username> <password>
if password is not supplied a strong one is generated.
The resulting jenv file is output (or saved to a file if -o option is provided)
juju remove-user <username>
doesn't actually remove the user. But mark them as inactive
add-user and remove-user aren't registered yet as they are useless without
login. But the details of this are still being worked out.
This branch also contains fixes for lp:1285256.
The EnvCommandBase struct includes a function for ensuring the envname is not ""
Description of the change
Preliminary support for basic juju id commands:
juju add-user <username> <password>
if password is not supplied uses gopass to take the password from the command line
juju remove-user <username>
doesn't actually remove the user. But mark them as inactive
add-user and remove-user aren't registered yet as they are useless without
login. But the details of this are still being worked out.
This branch also contains fixes for lp:1285256.
The EnvCommandBase struct includes a function for ensuring the envname is not "".
This replaces a review at https:/
Matthew Williams (mattyw) wrote : | # |
Matthew Williams (mattyw) wrote : | # |
On 2014/03/14 05:17:51, mattyw wrote:
> Please take a look.
This follows on from the review here:
https:/
William Reade (fwereade) wrote : | # |
Sorry, I don't think we're quite done here yet.
I am very happy with the EnvCommandBase stuff, though, so I'd swiftly
approve a CL that just landed those changes while we argue about the
UI/UX for user management.
https:/
File cmd/juju/
https:/
cmd/juju/
This has been scratching at the back of my mind for a while... "Base"
isn't quite the right term. "EnvCommand" -- or, hey, why not
"EnvironmentCom
not really itself a *command* in itself. Bah.
Nothing necessarily actionable here because I can't actually suggest
anything better, but I'd love it if we did come up with a better name.
https:/
File cmd/juju/adduser.go (right):
https:/
cmd/juju/
I'm still not really in love with allowing people to specify passwords
(especially in the absence of resetting post-distribution).
https:/
cmd/juju/
Any possibility we could design this to output a .jenv (*without* all
the bootstrap-config stuff) on stdout? I think that the
pass-jenvs-around model is pretty tolerable, really.
https:/
File cmd/juju/
https:/
cmd/juju/
{
TestAddUser, please
https:/
cmd/juju/
create user: user already exists")
we don't seem to have tests for the automatic password generation...
https:/
File cmd/juju/
https:/
cmd/juju/
Testremoveuser(c *gc.C) {
TestRemoveUser
https:/
cmd/juju/
no tests for CheckEmpty etc (same applies to AddUser as well fwiw)
https:/
File cmd/plugins/
https:/
cmd/plugins/
envcmd.
Hmm. Shouldn't these be using Ensure..?
https:/
File errors/errors.go (right):
https:/
Matthew Williams (mattyw) wrote : | # |
Updated the comments, stuff I haven't commented on is stuff I will do
https:/
File cmd/juju/adduser.go (right):
https:/
cmd/juju/
On 2014/03/18 01:11:39, fwereade wrote:
> I'm still not really in love with allowing people to specify passwords
> (especially in the absence of resetting post-distribution).
I'm not a huge fan of this either, it was added for two reasons:
1) Makes testing easier
2) Allows people to "script" adding users
Suggestions welcome
https:/
cmd/juju/
On 2014/03/18 01:11:39, fwereade wrote:
> Any possibility we could design this to output a .jenv (*without* all
the
> bootstrap-config stuff) on stdout? I think that the pass-jenvs-around
model is
> pretty tolerable, really.
Let's discuss this
https:/
File juju/osenv/
https:/
juju/osenv/
"launchpad.
On 2014/03/18 01:11:39, fwereade wrote:
> This is a bit surprising. Are you sure it's right?
I'll double check - I'm sure I was left with no choice at the time
https:/
File state/user.go (right):
https:/
state/user.go:32: return nil, fmt.Errorf(
On 2014/03/18 01:11:39, fwereade wrote:
> why can admin have an empty password set? (and wasn't there a constant
for
> "admin"?)
Admin does have a constant- must have missed this one.
I'm sure there was a reason for this - either we discussed it or not
having it caused problems - I'll double check
Matthew Williams (mattyw) wrote : | # |
https:/
File errors/errors.go (right):
https:/
errors/
On 2014/03/18 01:11:39, fwereade wrote:
> If we're touching this can we please do something about the
overwhelmingly
> shitty UX of being told "rc: 2", which means literally nothing to most
> semi-normal humans? just "subprocess exited with code 2" or
something... it'd be
> way better if we said *which* one but that's way out of scope.
Done.
https:/
File juju/osenv/
https:/
juju/osenv/
"launchpad.
On 2014/03/18 03:45:22, mattyw wrote:
> On 2014/03/18 01:11:39, fwereade wrote:
> > This is a bit surprising. Are you sure it's right?
> I'll double check - I'm sure I was left with no choice at the time
Done.
https:/
File state/user.go (right):
https:/
state/user.go:32: return nil, fmt.Errorf(
On 2014/03/18 03:45:22, mattyw wrote:
> On 2014/03/18 01:11:39, fwereade wrote:
> > why can admin have an empty password set? (and wasn't there a
constant for
> > "admin"?)
> Admin does have a constant- must have missed this one.
> I'm sure there was a reason for this - either we discussed it or not
having it
> caused problems - I'll double check
Done.
Matthew Williams (mattyw) wrote : | # |
Please take a look.
https:/
File cmd/juju/
https:/
cmd/juju/
{
On 2014/03/18 01:11:39, fwereade wrote:
> TestAddUser, please
Done.
https:/
cmd/juju/
create user: user already exists")
On 2014/03/18 01:11:39, fwereade wrote:
> we don't seem to have tests for the automatic password generation...
This isn't supported in the adduser stuff at the moment. Can I add this
in a separate branch?
https:/
File cmd/juju/
https:/
cmd/juju/
Testremoveuser(c *gc.C) {
On 2014/03/18 01:11:39, fwereade wrote:
> TestRemoveUser
Done.
https:/
cmd/juju/
On 2014/03/18 01:11:39, fwereade wrote:
> no tests for CheckEmpty etc (same applies to AddUser as well fwiw)
Done.
https:/
File cmd/plugins/
https:/
cmd/plugins/
envcmd.
On 2014/03/18 01:11:39, fwereade wrote:
> Hmm. Shouldn't these be using Ensure..?
Done.
https:/
File errors/errors.go (right):
https:/
errors/
than the default of 1 if
On 2014/03/18 01:11:39, fwereade wrote:
> and this comment in particular makes me wonder whether it's right to
have moved
> it. I think it *is* but it's a conceptual boundary violation to
mention cmd.Main
> in this context -- can we maybe just give it a generic name like
"ExitCodeError"
> and keep the special handling details in cmd.Main?
> Scope issues again, though, so you can TODO this with a bug tagged
tech-debt if
> you like.
Done.
William Reade (fwereade) wrote : | # |
TYVM for all the fixes -- a couple of bits need some work, but they'll
hopefully be changes that simplify/reduce scope rather than otherwise.
Let me know what you think.
https:/
File cmd/juju/adduser.go (right):
https:/
cmd/juju/
I'm not sure we really want this -- it STM to qualify as actual logic,
and thus to belong in Run rather than Init. It also should be using
stdin/out/err from the cmd.Context passed into run. Furthermore,
ReadPassword seems like overkill when we're just going to be storing it
in plaintext locally.
Let's just give them a default strong password in that case?
https:/
cmd/juju/
I feel this lot could be easier to follow. If we drop the terminal
stuff, how about something like:
switch len(args) {
case 0:
return fmt.Errorf("no username supplied")
case 1:
c.Password = utils.RandomPas
case 2:
c.Password = args[1]
default:
return cmd.CheckEmpty(
}
c.User = args[0]
return nil
..? YMMV, just a suggestion.
https:/
cmd/juju/
//info.
d
https:/
cmd/juju/
//info.
d
https:/
cmd/juju/
You need to ctx.AbsPath() this so we can test relative paths work right.
https:/
File environs/
https:/
environs/
I don't think we can just expose this type, it opens up all sorts of
cans of worms with Write and suchlike.
Would you extract the exported fields into a separate exported type, but
keep this one private, and embed the exported type therein? You'd need
to tweak the marshalling to read/write the embedded struct, not
environInfo itself, but it should otherwise be trivial. Make sense?
https:/
environs/
Yeah, this isn't going to be too happy if it's created without a .path.
Keep this type private, please.
Matthew Williams (mattyw) wrote : | # |
Please take a look.
https:/
File cmd/juju/adduser.go (right):
https:/
cmd/juju/
On 2014/03/27 12:14:34, fwereade wrote:
> I'm not sure we really want this -- it STM to qualify as actual logic,
and thus
> to belong in Run rather than Init. It also should be using
stdin/out/err from
> the cmd.Context passed into run. Furthermore, ReadPassword seems like
overkill
> when we're just going to be storing it in plaintext locally.
> Let's just give them a default strong password in that case?
Done.
https:/
cmd/juju/
On 2014/03/27 12:14:34, fwereade wrote:
> I feel this lot could be easier to follow. If we drop the terminal
stuff, how
> about something like:
> switch len(args) {
> case 0:
> return fmt.Errorf("no username supplied")
> case 1:
> c.Password = utils.RandomPas
> case 2:
> c.Password = args[1]
> default:
> return cmd.CheckEmpty(
> }
> c.User = args[0]
> return nil
> ..? YMMV, just a suggestion.
This is a great idea - let'd do this!
https:/
cmd/juju/
On 2014/03/27 12:14:34, fwereade wrote:
> I feel this lot could be easier to follow. If we drop the terminal
stuff, how
> about something like:
> switch len(args) {
> case 0:
> return fmt.Errorf("no username supplied")
> case 1:
> c.Password = utils.RandomPas
> case 2:
> c.Password = args[1]
> default:
> return cmd.CheckEmpty(
> }
> c.User = args[0]
> return nil
> ..? YMMV, just a suggestion.
Done.
https:/
cmd/juju/
//info.
On 2014/03/27 12:14:34, fwereade wrote:
> d
Done.
https:/
cmd/juju/
//info.
On 2014/03/27 12:14:34, fwereade wrote:
> d
Done.
https:/
cmd/juju/
On 2014/03/27 12:14:34, fwereade wrote:
> You need to ctx.AbsPath() this so we can test relative paths work
right.
Done.
William Reade (fwereade) wrote : | # |
Couple more tweaks to the command, and a couple of tests (and the json
marshalling); should be the last round.
https:/
File cmd/juju/adduser.go (right):
https:/
cmd/juju/
Mention that it writes to stdout by default?
https:/
cmd/juju/
This isn't using the context to print, which it should; but it can't,
because Init. And really, dammit, we shouldn't be erroring for reasons
unrelated to arg-parsing here at all. Sorry I didn't spot this earlier.
Let's just lose the printing, because it'll be written out anyway in a
mo -- or, ?nicer?, leave c.Password empty, and do the RandomPassword in
Run if c.Password == "".
https:/
cmd/juju/
I think I'd still write this stuff out before calling AddUser -- a
nonsense jenv can be regenerated, but you can't recover the password if
the process goes down before we write it out.
https:/
File cmd/juju/
https:/
cmd/juju/
string(
We should have some basic tests for --format to stdout and to -o. Don't
necessarily need to go overboard.
Matthew Williams (mattyw) wrote : | # |
Please take a look.
https:/
File cmd/juju/adduser.go (right):
https:/
cmd/juju/
On 2014/03/27 17:27:23, fwereade wrote:
> Mention that it writes to stdout by default?
Done.
https:/
cmd/juju/
On 2014/03/27 17:27:23, fwereade wrote:
> This isn't using the context to print, which it should; but it can't,
because
> Init. And really, dammit, we shouldn't be erroring for reasons
unrelated to
> arg-parsing here at all. Sorry I didn't spot this earlier.
> Let's just lose the printing, because it'll be written out anyway in a
mo -- or,
> ?nicer?, leave c.Password empty, and do the RandomPassword in Run if
c.Password
> == "".
Done.
https:/
cmd/juju/
On 2014/03/27 17:27:23, fwereade wrote:
> I think I'd still write this stuff out before calling AddUser -- a
nonsense jenv
> can be regenerated, but you can't recover the password if the process
goes down
> before we write it out.
Done.
William Reade (fwereade) wrote : | # |
LGTM with trivial fixes:
https:/
File cmd/juju/adduser.go (right):
https:/
cmd/juju/
to use the environment as that user.
A jenv file identifying the user and the environment will be written to
stdout, or to a path you specify with --output.
When add-environment lands, please add a note to this doc saying what
you can do with the jenv.
https:/
cmd/juju/
I rather like exporting the fields that get set up by Init at least --
and this field should really go next to Password.
https:/
File cmd/juju/
https:/
cmd/juju/
because yaml is evil, please test the output by parsing it, rather than
just checking for equality.
https:/
File environs/
https:/
environs/
d
Matthew Williams (mattyw) wrote : | # |
Please take a look.
https:/
File cmd/juju/adduser.go (right):
https:/
cmd/juju/
to use the environment as that user.
On 2014/03/28 10:09:22, fwereade wrote:
> A jenv file identifying the user and the environment will be written
to stdout,
> or to a path you specify with --output.
> When add-environment lands, please add a note to this doc saying what
you can do
> with the jenv.
Done.
https:/
cmd/juju/
On 2014/03/28 10:09:22, fwereade wrote:
> I rather like exporting the fields that get set up by Init at least --
and this
> field should really go next to Password.
Done.
https:/
File cmd/juju/
https:/
cmd/juju/
On 2014/03/28 10:09:22, fwereade wrote:
> because yaml is evil, please test the output by parsing it, rather
than just
> checking for equality.
Done.
https:/
File environs/
https:/
environs/
On 2014/03/28 10:09:22, fwereade wrote:
> d
Done.
William Reade (fwereade) wrote : | # |
LGTM, thanks
Matthew Williams (mattyw) wrote : | # |
Please take a look.
Go Bot (go-bot) wrote : | # |
The attempt to merge lp:~mattyw/juju-core/user-add-remove-cli into lp:juju-core failed. Below is the output from the failed tests.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
? launchpad.
? launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
? launchpad.
? launchpad.
ok launchpad.
-------
FAIL: bootstrap_
[LOG] 17.73050 DEBUG juju.environs.tools no architecture specified when finding tools, looking for any
[LOG] 17.73051 DEBUG juju.environs.tools no series specified when finding tools, looking for any
[LOG] 17.73059 DEBUG juju.environs.
[LOG] 17.73062 DEBUG juju.environs.
[LOG] 17.73067 DEBUG juju.environs.
[LOG] 17.73070 DEBUG juju.environs.
[LOG] 17.73211 INFO juju.environs.tools Writing tools/streams/
[LOG] 17.73241 INFO juju.environs.tools Writing tools/streams/
[LOG] 17.73290 INFO juju.provider.dummy reset environment
[LOG] 17.73654 INFO juju Reset successfully reset admin password
[LOG] 17.73733 DEBUG juju.environs.
clearing private storage
removing files: []
[LOG] 17.84044 WARNING juju.cmd.juju ignoring environments.yaml: using bootstrap config in file "/tmp/gocheck-
[LOG] 17.84120 DEBUG juju.environs ConfigForName found bootstrap config map[string]
Roger Peppe (rogpeppe) wrote : | # |
Looks great in general, with some comments and suggestions below.
https:/
File cmd/envcmd/
https:/
cmd/envcmd/
EnsureEnvNameSet() error {
I suggest that Init would be a more appropriate name for this method (we
want every command that embeds it to call it)
// Init initializes the Command.
func (c *Command) Init() error
https:/
File cmd/plugins/
https:/
cmd/plugins/
this should call EnsureEnvNameSet, presumably?
https:/
File environs/
https:/
environs/
Why does this need its own package?
https:/
File environs/
https:/
environs/
"error checking if provisioned: subprocess encountered error code 255")
I know it's not your doing, but I don't like seeing these error
messages. An error code tells us almost nothing. We really need to
change things so we use stderr when possible. No action required, just
saying.
https:/
File errors/errors.go (right):
https:/
errors/
If reasonable, I think this really does belong to cmd, because it
pertains directly to functionality in that package.
https:/
errors/
cmd.Main in here.
indeed
https:/
File juju/api.go (right):
https:/
juju/api.go:104: func NewUserManagerC
(*usermanager.
Rather than create a new function in juju for every single API client,
I'd prefer to just export NewAPIClient here, and for clients to use
facade New methods as appropriate.
So I'd delete NewKeyManagerClient and NewUserManagerC
methods to api.Client, KeyManager and UserManager.
That means a certain amount of shake up (the New functions need to
change to take an interface to avoid cyclic imports), but it's the same
pattern that works well for agents, and consistency is good.
Perhaps leave it like it is for now, and address that in a subsequent
CL?
Matthew Williams (mattyw) wrote : | # |
https:/
File cmd/envcmd/
https:/
cmd/envcmd/
EnsureEnvNameSet() error {
On 2014/03/31 14:21:12, rog wrote:
> I suggest that Init would be a more appropriate name for this method
(we want
> every command that embeds it to call it)
> // Init initializes the Command.
> func (c *Command) Init() error
Done.
https:/
File cmd/plugins/
https:/
cmd/plugins/
On 2014/03/31 14:21:12, rog wrote:
> this should call EnsureEnvNameSet, presumably?
Done.
https:/
File environs/
https:/
environs/
On 2014/03/31 14:21:12, rog wrote:
> Why does this need its own package?
Done.
https:/
File errors/errors.go (right):
https:/
errors/
On 2014/03/31 14:21:12, rog wrote:
> If reasonable, I think this really does belong to cmd, because it
pertains
> directly to functionality in that package.
Done.
https:/
errors/
cmd.Main in here.
On 2014/03/31 14:21:12, rog wrote:
> indeed
Done.
https:/
File juju/api.go (right):
https:/
juju/api.go:104: func NewUserManagerC
(*usermanager.
On 2014/03/31 14:21:12, rog wrote:
> Rather than create a new function in juju for every single API client,
I'd
> prefer to just export NewAPIClient here, and for clients to use facade
New
> methods as appropriate.
> So I'd delete NewKeyManagerClient and NewUserManagerC
methods to
> api.Client, KeyManager and UserManager.
https:/
> That means a certain amount of shake up (the New functions need to
change to
> take an interface to avoid cyclic imports), but it's the same pattern
that works
> well for agents, and consistency is good.
> Perhaps leave it like it is for now, and address that in a subsequent
CL?
https:/
File testing/environ.go (right):
https:/
testing/
[]TestFile) *FakeHome {
On 2014/03/31 14:21:12, rog wrote:
> Or perhaps change MakeSampleHome to be:
> func...
Matthew Williams (mattyw) wrote : | # |
Please take a look.
William Reade (fwereade) wrote : | # |
I'm a little bit irritated at the changes to EnsureEnvNameSet, and the
EnvironInfoData type, but neither decision is irrevocable and I really
cannot be bothered to fight them; let's just land this.
LGTM contingent on the other tweaks below, ping me if anything's not
clear.
https:/
File cmd/envcmd/
https:/
cmd/envcmd/
EnsureEnvNameSet() error {
On 2014/04/01 08:07:31, mattyw wrote:
> On 2014/03/31 14:21:12, rog wrote:
> > I suggest that Init would be a more appropriate name for this method
(we want
> > every command that embeds it to call it)
> >
> > // Init initializes the Command.
> > func (c *Command) Init() error
> Done.
I suggest that it would not, because it's aping the cmd.Command
interface but not actually satisfying it; and it has different
responsibilities, which might be most relevant at Init time but are
actually to do with, uh, ensuring an environment is set...
https:/
File environs/
https:/
environs/
On 2014/04/01 08:07:31, mattyw wrote:
> On 2014/03/31 14:21:12, rog wrote:
> > Why does this need its own package?
> Done.
What's the benefit of removing a small and focused package in favour of
jamming its contents into a tangentially-
sensible type name?
https:/
File environs/
https:/
environs/
"error checking if provisioned: subprocess encountered error code 255")
On 2014/03/31 14:21:12, rog wrote:
> I know it's not your doing, but I don't like seeing these error
messages. An
> error code tells us almost nothing. We really need to change things so
we use
> stderr when possible. No action required, just saying.
Progress not perfection. This beats the hell out of "rc:255" :).
https:/
File cmd/juju/adduser.go (right):
https:/
cmd/juju/
doesn't this return an error?
https:/
File cmd/juju/
https:/
cmd/juju/
[]string) (err error) {
This needs EnsureEnvNameSet as well
https:/
File juju/api.go (right):
https:/
juju/api.go:136: envs, err := environs.
Matthew Williams (mattyw) wrote : | # |
https:/
File cmd/juju/adduser.go (right):
https:/
cmd/juju/
On 2014/04/01 09:40:54, fwereade wrote:
> doesn't this return an error?
Done.
https:/
File cmd/juju/
https:/
cmd/juju/
[]string) (err error) {
On 2014/04/01 09:40:54, fwereade wrote:
> This needs EnsureEnvNameSet as well
Done.
https:/
File juju/api.go (right):
https:/
juju/api.go:136: envs, err := environs.
On 2014/04/01 09:40:54, fwereade wrote:
> Shouldn't this code have been deleted? We should never have an empty
envName to
> deal with now...
https:/
Matthew Williams (mattyw) wrote : | # |
Please take a look.
Preview Diff
1 | === modified file 'cmd/cmd.go' |
2 | --- cmd/cmd.go 2014-03-26 01:17:17 +0000 |
3 | +++ cmd/cmd.go 2014-04-01 14:32:48 +0000 |
4 | @@ -17,16 +17,16 @@ |
5 | "launchpad.net/gnuflag" |
6 | ) |
7 | |
8 | -type rcPassthroughError struct { |
9 | - code int |
10 | +type RcPassthroughError struct { |
11 | + Code int |
12 | } |
13 | |
14 | -func (e *rcPassthroughError) Error() string { |
15 | - return fmt.Sprintf("rc: %v", e.code) |
16 | +func (e *RcPassthroughError) Error() string { |
17 | + return fmt.Sprintf("subprocess encountered error code %v", e.Code) |
18 | } |
19 | |
20 | func IsRcPassthroughError(err error) bool { |
21 | - _, ok := err.(*rcPassthroughError) |
22 | + _, ok := err.(*RcPassthroughError) |
23 | return ok |
24 | } |
25 | |
26 | @@ -34,7 +34,7 @@ |
27 | // return code from the cmd.Main function rather than the default of 1 if |
28 | // there is an error. |
29 | func NewRcPassthroughError(code int) error { |
30 | - return &rcPassthroughError{code} |
31 | + return &RcPassthroughError{code} |
32 | } |
33 | |
34 | // ErrSilent can be returned from Run to signal that Main should exit with |
35 | @@ -243,7 +243,7 @@ |
36 | } |
37 | if err := c.Run(ctx); err != nil { |
38 | if IsRcPassthroughError(err) { |
39 | - return err.(*rcPassthroughError).code |
40 | + return err.(*RcPassthroughError).Code |
41 | } |
42 | if err != ErrSilent { |
43 | fmt.Fprintf(ctx.Stderr, "error: %v\n", err) |
44 | |
45 | === added directory 'cmd/envcmd' |
46 | === renamed file 'cmd/environmentcommand.go' => 'cmd/envcmd/environmentcommand.go' |
47 | --- cmd/environmentcommand.go 2014-01-22 22:48:54 +0000 |
48 | +++ cmd/envcmd/environmentcommand.go 2014-04-01 14:32:48 +0000 |
49 | @@ -1,7 +1,7 @@ |
50 | // Copyright 2013 Canonical Ltd. |
51 | // Licensed under the AGPLv3, see LICENCE file for details. |
52 | |
53 | -package cmd |
54 | +package envcmd |
55 | |
56 | import ( |
57 | "fmt" |
58 | @@ -12,6 +12,8 @@ |
59 | |
60 | "launchpad.net/gnuflag" |
61 | |
62 | + "launchpad.net/juju-core/cmd" |
63 | + "launchpad.net/juju-core/environs" |
64 | "launchpad.net/juju-core/juju/osenv" |
65 | ) |
66 | |
67 | @@ -20,7 +22,7 @@ |
68 | // The purpose of EnvCommandBase is to provide a default member and flag |
69 | // setting for commands that deal across different environments. |
70 | type EnvCommandBase struct { |
71 | - CommandBase |
72 | + cmd.CommandBase |
73 | EnvName string |
74 | } |
75 | |
76 | @@ -62,6 +64,17 @@ |
77 | return ReadCurrentEnvironment() |
78 | } |
79 | |
80 | +func (c *EnvCommandBase) Init() error { |
81 | + if c.EnvName == "" { |
82 | + envs, err := environs.ReadEnvirons("") |
83 | + if err != nil { |
84 | + return err |
85 | + } |
86 | + c.EnvName = envs.Default |
87 | + } |
88 | + return nil |
89 | +} |
90 | + |
91 | func (c *EnvCommandBase) SetFlags(f *gnuflag.FlagSet) { |
92 | defaultEnv := getDefaultEnvironment() |
93 | f.StringVar(&c.EnvName, "e", defaultEnv, "juju environment to operate in") |
94 | |
95 | === renamed file 'cmd/environmentcommand_test.go' => 'cmd/envcmd/environmentcommand_test.go' |
96 | --- cmd/environmentcommand_test.go 2014-01-22 22:48:54 +0000 |
97 | +++ cmd/envcmd/environmentcommand_test.go 2014-04-01 14:32:48 +0000 |
98 | @@ -1,27 +1,30 @@ |
99 | // Copyright 2013 Canonical Ltd. |
100 | // Licensed under the AGPLv3, see LICENCE file for details. |
101 | |
102 | -package cmd_test |
103 | +package envcmd_test |
104 | |
105 | import ( |
106 | "io/ioutil" |
107 | "os" |
108 | + "testing" |
109 | |
110 | gc "launchpad.net/gocheck" |
111 | |
112 | - "launchpad.net/juju-core/cmd" |
113 | + "launchpad.net/juju-core/cmd/envcmd" |
114 | "launchpad.net/juju-core/juju/osenv" |
115 | - "launchpad.net/juju-core/testing" |
116 | + jujutesting "launchpad.net/juju-core/testing" |
117 | ) |
118 | |
119 | type EnvironmentCommandSuite struct { |
120 | - home *testing.FakeHome |
121 | + home *jujutesting.FakeHome |
122 | } |
123 | |
124 | var _ = gc.Suite(&EnvironmentCommandSuite{}) |
125 | |
126 | +func Test(t *testing.T) { gc.TestingT(t) } |
127 | + |
128 | func (s *EnvironmentCommandSuite) SetUpTest(c *gc.C) { |
129 | - s.home = testing.MakeEmptyFakeHome(c) |
130 | + s.home = jujutesting.MakeEmptyFakeHome(c) |
131 | } |
132 | |
133 | func (s *EnvironmentCommandSuite) TearDownTest(c *gc.C) { |
134 | @@ -29,54 +32,54 @@ |
135 | } |
136 | |
137 | func (s *EnvironmentCommandSuite) TestReadCurrentEnvironmentUnset(c *gc.C) { |
138 | - env := cmd.ReadCurrentEnvironment() |
139 | + env := envcmd.ReadCurrentEnvironment() |
140 | c.Assert(env, gc.Equals, "") |
141 | } |
142 | |
143 | func (s *EnvironmentCommandSuite) TestReadCurrentEnvironmentSet(c *gc.C) { |
144 | - err := cmd.WriteCurrentEnvironment("fubar") |
145 | + err := envcmd.WriteCurrentEnvironment("fubar") |
146 | c.Assert(err, gc.IsNil) |
147 | - env := cmd.ReadCurrentEnvironment() |
148 | + env := envcmd.ReadCurrentEnvironment() |
149 | c.Assert(env, gc.Equals, "fubar") |
150 | } |
151 | |
152 | func (s *EnvironmentCommandSuite) TestGetDefaultEnvironmentNothingSet(c *gc.C) { |
153 | - env := cmd.GetDefaultEnvironment() |
154 | + env := envcmd.GetDefaultEnvironment() |
155 | c.Assert(env, gc.Equals, "") |
156 | } |
157 | |
158 | func (s *EnvironmentCommandSuite) TestGetDefaultEnvironmentCurrentEnvironmentSet(c *gc.C) { |
159 | - err := cmd.WriteCurrentEnvironment("fubar") |
160 | + err := envcmd.WriteCurrentEnvironment("fubar") |
161 | c.Assert(err, gc.IsNil) |
162 | - env := cmd.GetDefaultEnvironment() |
163 | + env := envcmd.GetDefaultEnvironment() |
164 | c.Assert(env, gc.Equals, "fubar") |
165 | } |
166 | |
167 | func (s *EnvironmentCommandSuite) TestGetDefaultEnvironmentJujuEnvSet(c *gc.C) { |
168 | os.Setenv(osenv.JujuEnvEnvKey, "magic") |
169 | - env := cmd.GetDefaultEnvironment() |
170 | + env := envcmd.GetDefaultEnvironment() |
171 | c.Assert(env, gc.Equals, "magic") |
172 | } |
173 | |
174 | func (s *EnvironmentCommandSuite) TestGetDefaultEnvironmentBothSet(c *gc.C) { |
175 | os.Setenv(osenv.JujuEnvEnvKey, "magic") |
176 | - err := cmd.WriteCurrentEnvironment("fubar") |
177 | + err := envcmd.WriteCurrentEnvironment("fubar") |
178 | c.Assert(err, gc.IsNil) |
179 | - env := cmd.GetDefaultEnvironment() |
180 | + env := envcmd.GetDefaultEnvironment() |
181 | c.Assert(env, gc.Equals, "magic") |
182 | } |
183 | |
184 | func (s *EnvironmentCommandSuite) TestWriteAddsNewline(c *gc.C) { |
185 | - err := cmd.WriteCurrentEnvironment("fubar") |
186 | + err := envcmd.WriteCurrentEnvironment("fubar") |
187 | c.Assert(err, gc.IsNil) |
188 | - current, err := ioutil.ReadFile(cmd.GetCurrentEnvironmentFilePath()) |
189 | + current, err := ioutil.ReadFile(envcmd.GetCurrentEnvironmentFilePath()) |
190 | c.Assert(err, gc.IsNil) |
191 | c.Assert(string(current), gc.Equals, "fubar\n") |
192 | } |
193 | |
194 | func (*EnvironmentCommandSuite) TestErrorWritingFile(c *gc.C) { |
195 | // Can't write a file over a directory. |
196 | - os.MkdirAll(cmd.GetCurrentEnvironmentFilePath(), 0777) |
197 | - err := cmd.WriteCurrentEnvironment("fubar") |
198 | + os.MkdirAll(envcmd.GetCurrentEnvironmentFilePath(), 0777) |
199 | + err := envcmd.WriteCurrentEnvironment("fubar") |
200 | c.Assert(err, gc.ErrorMatches, "unable to write to the environment file: .*") |
201 | } |
202 | |
203 | === renamed file 'cmd/export_test.go' => 'cmd/envcmd/export_test.go' |
204 | --- cmd/export_test.go 2014-03-25 22:31:46 +0000 |
205 | +++ cmd/envcmd/export_test.go 2014-04-01 14:32:48 +0000 |
206 | @@ -1,7 +1,7 @@ |
207 | // Copyright 2013 Canonical Ltd. |
208 | // Licensed under the AGPLv3, see LICENCE file for details. |
209 | |
210 | -package cmd |
211 | +package envcmd |
212 | |
213 | var ( |
214 | GetDefaultEnvironment = getDefaultEnvironment |
215 | |
216 | === modified file 'cmd/juju/addmachine.go' |
217 | --- cmd/juju/addmachine.go 2014-02-22 15:40:29 +0000 |
218 | +++ cmd/juju/addmachine.go 2014-04-01 14:32:48 +0000 |
219 | @@ -10,6 +10,7 @@ |
220 | "launchpad.net/gnuflag" |
221 | |
222 | "launchpad.net/juju-core/cmd" |
223 | + "launchpad.net/juju-core/cmd/envcmd" |
224 | "launchpad.net/juju-core/constraints" |
225 | "launchpad.net/juju-core/environs/manual" |
226 | "launchpad.net/juju-core/instance" |
227 | @@ -56,7 +57,7 @@ |
228 | |
229 | // AddMachineCommand starts a new machine and registers it in the environment. |
230 | type AddMachineCommand struct { |
231 | - cmd.EnvCommandBase |
232 | + envcmd.EnvCommandBase |
233 | // If specified, use this series, else use the environment default-series |
234 | Series string |
235 | // If specified, these constraints are merged with those already in the environment. |
236 | @@ -82,6 +83,10 @@ |
237 | } |
238 | |
239 | func (c *AddMachineCommand) Init(args []string) error { |
240 | + err := c.EnvCommandBase.Init() |
241 | + if err != nil { |
242 | + return err |
243 | + } |
244 | if c.Constraints.Container != nil { |
245 | return fmt.Errorf("container constraint %q not allowed when adding a machine", *c.Constraints.Container) |
246 | } |
247 | |
248 | === modified file 'cmd/juju/addrelation.go' |
249 | --- cmd/juju/addrelation.go 2013-11-05 04:12:48 +0000 |
250 | +++ cmd/juju/addrelation.go 2014-04-01 14:32:48 +0000 |
251 | @@ -7,12 +7,13 @@ |
252 | "fmt" |
253 | |
254 | "launchpad.net/juju-core/cmd" |
255 | + "launchpad.net/juju-core/cmd/envcmd" |
256 | "launchpad.net/juju-core/juju" |
257 | ) |
258 | |
259 | // AddRelationCommand adds a relation between two service endpoints. |
260 | type AddRelationCommand struct { |
261 | - cmd.EnvCommandBase |
262 | + envcmd.EnvCommandBase |
263 | Endpoints []string |
264 | } |
265 | |
266 | @@ -25,6 +26,10 @@ |
267 | } |
268 | |
269 | func (c *AddRelationCommand) Init(args []string) error { |
270 | + err := c.EnvCommandBase.Init() |
271 | + if err != nil { |
272 | + return err |
273 | + } |
274 | if len(args) != 2 { |
275 | return fmt.Errorf("a relation must involve two services") |
276 | } |
277 | |
278 | === modified file 'cmd/juju/addunit.go' |
279 | --- cmd/juju/addunit.go 2013-10-08 14:53:20 +0000 |
280 | +++ cmd/juju/addunit.go 2014-04-01 14:32:48 +0000 |
281 | @@ -10,6 +10,7 @@ |
282 | "launchpad.net/gnuflag" |
283 | |
284 | "launchpad.net/juju-core/cmd" |
285 | + "launchpad.net/juju-core/cmd/envcmd" |
286 | "launchpad.net/juju-core/juju" |
287 | ) |
288 | |
289 | @@ -42,7 +43,7 @@ |
290 | |
291 | // AddUnitCommand is responsible adding additional units to a service. |
292 | type AddUnitCommand struct { |
293 | - cmd.EnvCommandBase |
294 | + envcmd.EnvCommandBase |
295 | UnitCommandBase |
296 | ServiceName string |
297 | } |
298 | |
299 | === added file 'cmd/juju/adduser.go' |
300 | --- cmd/juju/adduser.go 1970-01-01 00:00:00 +0000 |
301 | +++ cmd/juju/adduser.go 2014-04-01 14:32:48 +0000 |
302 | @@ -0,0 +1,103 @@ |
303 | +// Copyright 2012, 2013, 2014 Canonical Ltd. |
304 | +// Licensed under the AGPLv3, see LICENCE file for details. |
305 | + |
306 | +package main |
307 | + |
308 | +import ( |
309 | + "fmt" |
310 | + |
311 | + "launchpad.net/gnuflag" |
312 | + "launchpad.net/juju-core/cmd" |
313 | + "launchpad.net/juju-core/cmd/envcmd" |
314 | + "launchpad.net/juju-core/environs/configstore" |
315 | + "launchpad.net/juju-core/juju" |
316 | + "launchpad.net/juju-core/utils" |
317 | +) |
318 | + |
319 | +const addUserDoc = ` |
320 | +Add users to an existing environment |
321 | +The user information is stored within an existing environment, and will be lost |
322 | +when the environent is destroyed. |
323 | +A jenv file identifying the user and the environment will be written to stdout, |
324 | +or to a path you specify with --output. |
325 | + |
326 | +Examples: |
327 | + juju add-user foobar mypass (Add user foobar with password mypass) |
328 | + juju add-user foobar (Add user foobar. A strong password will be generated and printed) |
329 | + juju add-user foobar -o filename (Add user foobar (with generated password) and save example jenv file to filename) |
330 | +` |
331 | + |
332 | +type AddUserCommand struct { |
333 | + envcmd.EnvCommandBase |
334 | + User string |
335 | + Password string |
336 | + GeneratePassword bool |
337 | + out cmd.Output |
338 | +} |
339 | + |
340 | +func (c *AddUserCommand) Info() *cmd.Info { |
341 | + return &cmd.Info{ |
342 | + Name: "add-user", |
343 | + Args: "<username> <password>", |
344 | + Purpose: "adds a user", |
345 | + Doc: addUserDoc, |
346 | + } |
347 | +} |
348 | + |
349 | +func (c *AddUserCommand) SetFlags(f *gnuflag.FlagSet) { |
350 | + c.out.AddFlags(f, "yaml", map[string]cmd.Formatter{ |
351 | + "yaml": cmd.FormatYaml, |
352 | + "json": cmd.FormatJson, |
353 | + }) |
354 | +} |
355 | +func (c *AddUserCommand) Init(args []string) error { |
356 | + err := c.EnvCommandBase.Init() |
357 | + if err != nil { |
358 | + return err |
359 | + } |
360 | + switch len(args) { |
361 | + case 0: |
362 | + return fmt.Errorf("no username supplied") |
363 | + case 1: |
364 | + c.GeneratePassword = true |
365 | + case 2: |
366 | + c.Password = args[1] |
367 | + default: |
368 | + return cmd.CheckEmpty(args[2:]) |
369 | + } |
370 | + |
371 | + c.User = args[0] |
372 | + return nil |
373 | +} |
374 | + |
375 | +func (c *AddUserCommand) Run(ctx *cmd.Context) error { |
376 | + store, err := configstore.Default() |
377 | + if err != nil { |
378 | + return fmt.Errorf("cannot open environment info storage: %v", err) |
379 | + } |
380 | + storeInfo, err := store.ReadInfo(c.EnvName) |
381 | + if err != nil { |
382 | + return err |
383 | + } |
384 | + client, err := juju.NewUserManagerClient(c.EnvName) |
385 | + if err != nil { |
386 | + return err |
387 | + } |
388 | + defer client.Close() |
389 | + if c.GeneratePassword { |
390 | + c.Password, err = utils.RandomPassword() |
391 | + if err != nil { |
392 | + return fmt.Errorf("Failed to generate password: %v", err) |
393 | + } |
394 | + } |
395 | + outputInfo := configstore.EnvironInfoData{} |
396 | + outputInfo.User = c.User |
397 | + outputInfo.Password = c.Password |
398 | + outputInfo.StateServers = storeInfo.APIEndpoint().Addresses |
399 | + outputInfo.CACert = storeInfo.APIEndpoint().CACert |
400 | + err = c.out.Write(ctx, outputInfo) |
401 | + if err != nil { |
402 | + return err |
403 | + } |
404 | + return client.AddUser(c.User, c.Password) |
405 | +} |
406 | |
407 | === added file 'cmd/juju/adduser_test.go' |
408 | --- cmd/juju/adduser_test.go 1970-01-01 00:00:00 +0000 |
409 | +++ cmd/juju/adduser_test.go 2014-04-01 14:32:48 +0000 |
410 | @@ -0,0 +1,106 @@ |
411 | +// Copyright 2014 Canonical Ltd. |
412 | +// Licensed under the AGPLv3, see LICENCE file for details. |
413 | + |
414 | +package main |
415 | + |
416 | +import ( |
417 | + "bytes" |
418 | + "io/ioutil" |
419 | + |
420 | + gc "launchpad.net/gocheck" |
421 | + "launchpad.net/goyaml" |
422 | + jujutesting "launchpad.net/juju-core/juju/testing" |
423 | + |
424 | + "launchpad.net/juju-core/testing" |
425 | +) |
426 | + |
427 | +// All of the functionality of the AddUser api call is contained elsewhere |
428 | +// This suite provides basic tests for the AddUser command |
429 | +type AddUserSuite struct { |
430 | + jujutesting.RepoSuite |
431 | +} |
432 | + |
433 | +var _ = gc.Suite(&AddUserSuite{}) |
434 | + |
435 | +func (s *AddUserSuite) TestAddUser(c *gc.C) { |
436 | + |
437 | + _, err := testing.RunCommand(c, &AddUserCommand{}, []string{"foobar", "password"}) |
438 | + c.Assert(err, gc.IsNil) |
439 | + |
440 | + _, err = testing.RunCommand(c, &AddUserCommand{}, []string{"foobar", "newpassword"}) |
441 | + c.Assert(err, gc.ErrorMatches, "Failed to create user: user already exists") |
442 | +} |
443 | + |
444 | +func (s *AddUserSuite) TestTooManyArgs(c *gc.C) { |
445 | + _, err := testing.RunCommand(c, &AddUserCommand{}, []string{"foobar", "password", "whoops"}) |
446 | + c.Assert(err, gc.ErrorMatches, `unrecognized args: \["whoops"\]`) |
447 | +} |
448 | + |
449 | +func (s *AddUserSuite) TestNotEnoughArgs(c *gc.C) { |
450 | + _, err := testing.RunCommand(c, &AddUserCommand{}, []string{}) |
451 | + c.Assert(err, gc.ErrorMatches, `no username supplied`) |
452 | +} |
453 | + |
454 | +func (s *AddUserSuite) TestJenvYamlFileOutput(c *gc.C) { |
455 | + expected := map[string]interface{}{ |
456 | + "user": "foobar", |
457 | + "password": "password", |
458 | + "state-servers": []interface{}{}, |
459 | + "ca-cert": ""} |
460 | + tempFile, err := ioutil.TempFile("", "adduser-test") |
461 | + tempFile.Close() |
462 | + c.Assert(err, gc.IsNil) |
463 | + _, err = testing.RunCommand(c, &AddUserCommand{}, []string{"foobar", "password", "-o", tempFile.Name()}) |
464 | + c.Assert(err, gc.IsNil) |
465 | + data, err := ioutil.ReadFile(tempFile.Name()) |
466 | + result := map[string]interface{}{} |
467 | + err = goyaml.Unmarshal(data, &result) |
468 | + c.Assert(err, gc.IsNil) |
469 | + c.Assert(result, gc.DeepEquals, expected) |
470 | +} |
471 | + |
472 | +func (s *AddUserSuite) TestJenvYamlOutput(c *gc.C) { |
473 | + expected := map[string]interface{}{ |
474 | + "user": "foobar", |
475 | + "password": "password", |
476 | + "state-servers": []interface{}{}, |
477 | + "ca-cert": ""} |
478 | + ctx, err := testing.RunCommand(c, &AddUserCommand{}, []string{"foobar", "password"}) |
479 | + c.Assert(err, gc.IsNil) |
480 | + stdout := ctx.Stdout.(*bytes.Buffer).Bytes() |
481 | + result := map[string]interface{}{} |
482 | + err = goyaml.Unmarshal(stdout, &result) |
483 | + c.Assert(err, gc.IsNil) |
484 | + c.Assert(result, gc.DeepEquals, expected) |
485 | +} |
486 | + |
487 | +func (s *AddUserSuite) TestJenvJsonOutput(c *gc.C) { |
488 | + expected := `{"User":"foobar","Password":"password","state-servers":null,"ca-cert":""} |
489 | +` |
490 | + tempFile, err := ioutil.TempFile("", "adduser-test") |
491 | + tempFile.Close() |
492 | + c.Assert(err, gc.IsNil) |
493 | + _, err = testing.RunCommand(c, &AddUserCommand{}, []string{"foobar", "password", "-o", tempFile.Name(), "--format", "json"}) |
494 | + c.Assert(err, gc.IsNil) |
495 | + data, err := ioutil.ReadFile(tempFile.Name()) |
496 | + c.Assert(string(data), gc.DeepEquals, expected) |
497 | +} |
498 | + |
499 | +func (s *AddUserSuite) TestJenvJsonFileOutput(c *gc.C) { |
500 | + expected := `{"User":"foobar","Password":"password","state-servers":null,"ca-cert":""} |
501 | +` |
502 | + ctx, err := testing.RunCommand(c, &AddUserCommand{}, []string{"foobar", "password", "--format", "json"}) |
503 | + c.Assert(err, gc.IsNil) |
504 | + stdout := ctx.Stdout.(*bytes.Buffer).String() |
505 | + c.Assert(stdout, gc.DeepEquals, expected) |
506 | +} |
507 | + |
508 | +func (s *AddUserSuite) TestGeneratePassword(c *gc.C) { |
509 | + ctx, err := testing.RunCommand(c, &AddUserCommand{}, []string{"foobar"}) |
510 | + c.Assert(err, gc.IsNil) |
511 | + stdout := ctx.Stdout.(*bytes.Buffer).Bytes() |
512 | + var d map[string]interface{} |
513 | + err = goyaml.Unmarshal(stdout, &d) |
514 | + c.Assert(err, gc.IsNil) |
515 | + c.Assert(d["user"], gc.DeepEquals, "foobar") |
516 | +} |
517 | |
518 | === modified file 'cmd/juju/authorisedkeys_add.go' |
519 | --- cmd/juju/authorisedkeys_add.go 2013-12-13 06:53:01 +0000 |
520 | +++ cmd/juju/authorisedkeys_add.go 2014-04-01 14:32:48 +0000 |
521 | @@ -10,6 +10,7 @@ |
522 | "launchpad.net/gnuflag" |
523 | |
524 | "launchpad.net/juju-core/cmd" |
525 | + "launchpad.net/juju-core/cmd/envcmd" |
526 | "launchpad.net/juju-core/juju" |
527 | ) |
528 | |
529 | @@ -19,7 +20,7 @@ |
530 | |
531 | // AddKeysCommand is used to add a new authorized ssh key for a user. |
532 | type AddKeysCommand struct { |
533 | - cmd.EnvCommandBase |
534 | + envcmd.EnvCommandBase |
535 | user string |
536 | sshKeys []string |
537 | } |
538 | @@ -34,6 +35,10 @@ |
539 | } |
540 | |
541 | func (c *AddKeysCommand) Init(args []string) error { |
542 | + err := c.EnvCommandBase.Init() |
543 | + if err != nil { |
544 | + return err |
545 | + } |
546 | switch len(args) { |
547 | case 0: |
548 | return errors.New("no ssh key specified") |
549 | |
550 | === modified file 'cmd/juju/authorisedkeys_delete.go' |
551 | --- cmd/juju/authorisedkeys_delete.go 2013-12-13 06:53:01 +0000 |
552 | +++ cmd/juju/authorisedkeys_delete.go 2014-04-01 14:32:48 +0000 |
553 | @@ -10,6 +10,7 @@ |
554 | "launchpad.net/gnuflag" |
555 | |
556 | "launchpad.net/juju-core/cmd" |
557 | + "launchpad.net/juju-core/cmd/envcmd" |
558 | "launchpad.net/juju-core/juju" |
559 | ) |
560 | |
561 | @@ -21,7 +22,7 @@ |
562 | |
563 | // DeleteKeysCommand is used to delete authorized ssh keys for a user. |
564 | type DeleteKeysCommand struct { |
565 | - cmd.EnvCommandBase |
566 | + envcmd.EnvCommandBase |
567 | user string |
568 | keyIds []string |
569 | } |
570 | @@ -36,6 +37,10 @@ |
571 | } |
572 | |
573 | func (c *DeleteKeysCommand) Init(args []string) error { |
574 | + err := c.EnvCommandBase.Init() |
575 | + if err != nil { |
576 | + return err |
577 | + } |
578 | switch len(args) { |
579 | case 0: |
580 | return errors.New("no ssh key id specified") |
581 | |
582 | === modified file 'cmd/juju/authorisedkeys_import.go' |
583 | --- cmd/juju/authorisedkeys_import.go 2013-12-13 06:53:01 +0000 |
584 | +++ cmd/juju/authorisedkeys_import.go 2014-04-01 14:32:48 +0000 |
585 | @@ -10,6 +10,7 @@ |
586 | "launchpad.net/gnuflag" |
587 | |
588 | "launchpad.net/juju-core/cmd" |
589 | + "launchpad.net/juju-core/cmd/envcmd" |
590 | "launchpad.net/juju-core/juju" |
591 | ) |
592 | |
593 | @@ -20,7 +21,7 @@ |
594 | |
595 | // ImportKeysCommand is used to add new authorized ssh keys for a user. |
596 | type ImportKeysCommand struct { |
597 | - cmd.EnvCommandBase |
598 | + envcmd.EnvCommandBase |
599 | user string |
600 | sshKeyIds []string |
601 | } |
602 | @@ -35,6 +36,10 @@ |
603 | } |
604 | |
605 | func (c *ImportKeysCommand) Init(args []string) error { |
606 | + err := c.EnvCommandBase.Init() |
607 | + if err != nil { |
608 | + return err |
609 | + } |
610 | switch len(args) { |
611 | case 0: |
612 | return errors.New("no ssh key id specified") |
613 | |
614 | === modified file 'cmd/juju/authorisedkeys_list.go' |
615 | --- cmd/juju/authorisedkeys_list.go 2013-12-12 22:14:52 +0000 |
616 | +++ cmd/juju/authorisedkeys_list.go 2014-04-01 14:32:48 +0000 |
617 | @@ -10,6 +10,7 @@ |
618 | "launchpad.net/gnuflag" |
619 | |
620 | "launchpad.net/juju-core/cmd" |
621 | + "launchpad.net/juju-core/cmd/envcmd" |
622 | "launchpad.net/juju-core/juju" |
623 | "launchpad.net/juju-core/utils/ssh" |
624 | ) |
625 | @@ -22,7 +23,7 @@ |
626 | |
627 | // ListKeysCommand is used to list the authorized ssh keys. |
628 | type ListKeysCommand struct { |
629 | - cmd.EnvCommandBase |
630 | + envcmd.EnvCommandBase |
631 | showFullKey bool |
632 | user string |
633 | } |
634 | @@ -41,6 +42,14 @@ |
635 | f.StringVar(&c.user, "user", "admin", "the user for which to list the keys") |
636 | } |
637 | |
638 | +func (c *ListKeysCommand) Init(args []string) error { |
639 | + err := c.EnvCommandBase.Init() |
640 | + if err != nil { |
641 | + return err |
642 | + } |
643 | + return cmd.CheckEmpty(args) |
644 | +} |
645 | + |
646 | func (c *ListKeysCommand) Run(context *cmd.Context) error { |
647 | client, err := juju.NewKeyManagerClient(c.EnvName) |
648 | if err != nil { |
649 | |
650 | === modified file 'cmd/juju/bootstrap.go' |
651 | --- cmd/juju/bootstrap.go 2014-03-26 03:30:35 +0000 |
652 | +++ cmd/juju/bootstrap.go 2014-04-01 14:32:48 +0000 |
653 | @@ -12,6 +12,7 @@ |
654 | |
655 | "launchpad.net/juju-core/charm" |
656 | "launchpad.net/juju-core/cmd" |
657 | + "launchpad.net/juju-core/cmd/envcmd" |
658 | "launchpad.net/juju-core/constraints" |
659 | "launchpad.net/juju-core/environs/bootstrap" |
660 | "launchpad.net/juju-core/environs/imagemetadata" |
661 | @@ -58,7 +59,7 @@ |
662 | // BootstrapCommand is responsible for launching the first machine in a juju |
663 | // environment, and setting up everything necessary to continue working. |
664 | type BootstrapCommand struct { |
665 | - cmd.EnvCommandBase |
666 | + envcmd.EnvCommandBase |
667 | Constraints constraints.Value |
668 | UploadTools bool |
669 | Series []string |
670 | @@ -82,6 +83,10 @@ |
671 | } |
672 | |
673 | func (c *BootstrapCommand) Init(args []string) (err error) { |
674 | + err = c.EnvCommandBase.Init() |
675 | + if err != nil { |
676 | + return |
677 | + } |
678 | if len(c.Series) > 0 && !c.UploadTools { |
679 | return fmt.Errorf("--series requires --upload-tools") |
680 | } |
681 | |
682 | === modified file 'cmd/juju/bootstrap_test.go' |
683 | --- cmd/juju/bootstrap_test.go 2014-03-25 08:47:50 +0000 |
684 | +++ cmd/juju/bootstrap_test.go 2014-04-01 14:32:48 +0000 |
685 | @@ -374,8 +374,7 @@ |
686 | ctx2 := coretesting.Context(c) |
687 | code2 := cmd.Main(&BootstrapCommand{}, ctx2, nil) |
688 | c.Check(code2, gc.Equals, 1) |
689 | - expectedErrText := "Bootstrap failed, destroying environment\n" |
690 | - expectedErrText += "error: environment is already bootstrapped\n" |
691 | + expectedErrText := "error: environment is already bootstrapped\n" |
692 | c.Check(coretesting.Stderr(ctx2), gc.Equals, expectedErrText) |
693 | c.Check(coretesting.Stdout(ctx2), gc.Equals, "") |
694 | } |
695 | @@ -542,8 +541,7 @@ |
696 | code := cmd.Main(&BootstrapCommand{}, context, nil) |
697 | c.Assert(code, gc.Equals, 1) |
698 | errText := context.Stderr.(*bytes.Buffer).String() |
699 | - expectedErrText := "Bootstrap failed, destroying environment\n" |
700 | - expectedErrText += "error: cannot upload bootstrap tools: Juju cannot bootstrap because no tools are available for your environment(.|\n)*" |
701 | + expectedErrText := "error: cannot upload bootstrap tools: Juju cannot bootstrap because no tools are available for your environment(.|\n)*" |
702 | c.Assert(errText, gc.Matches, expectedErrText) |
703 | } |
704 | |
705 | @@ -559,7 +557,6 @@ |
706 | c.Assert(code, gc.Equals, 1) |
707 | errText := context.Stderr.(*bytes.Buffer).String() |
708 | expectedErrText := "uploading tools for series \\[precise raring\\]\n" |
709 | - expectedErrText += "Bootstrap failed, destroying environment\n" |
710 | expectedErrText += "error: cannot upload bootstrap tools: an error\n" |
711 | c.Assert(errText, gc.Matches, expectedErrText) |
712 | } |
713 | |
714 | === modified file 'cmd/juju/cmd_test.go' |
715 | --- cmd/juju/cmd_test.go 2014-03-24 10:42:51 +0000 |
716 | +++ cmd/juju/cmd_test.go 2014-04-01 14:32:48 +0000 |
717 | @@ -97,7 +97,7 @@ |
718 | c.Logf("test %d", i) |
719 | com, args := cmdFunc() |
720 | testInit(c, com, args, "") |
721 | - assertConnName(c, com, "") |
722 | + assertConnName(c, com, "peckham") |
723 | |
724 | com, args = cmdFunc() |
725 | testInit(c, com, append(args, "-e", "walthamstow"), "") |
726 | @@ -192,6 +192,7 @@ |
727 | if com.RepoPath == "" { |
728 | com.RepoPath = "/path/to/repo" |
729 | } |
730 | + com.EnvCommandBase.EnvName = "peckham" |
731 | } |
732 | |
733 | func initDeployCommand(args ...string) (*DeployCommand, error) { |
734 | |
735 | === modified file 'cmd/juju/constraints.go' |
736 | --- cmd/juju/constraints.go 2013-12-17 18:21:26 +0000 |
737 | +++ cmd/juju/constraints.go 2014-04-01 14:32:48 +0000 |
738 | @@ -9,6 +9,7 @@ |
739 | "launchpad.net/gnuflag" |
740 | |
741 | "launchpad.net/juju-core/cmd" |
742 | + "launchpad.net/juju-core/cmd/envcmd" |
743 | "launchpad.net/juju-core/constraints" |
744 | "launchpad.net/juju-core/juju" |
745 | "launchpad.net/juju-core/names" |
746 | @@ -51,7 +52,7 @@ |
747 | |
748 | // GetConstraintsCommand shows the constraints for a service or environment. |
749 | type GetConstraintsCommand struct { |
750 | - cmd.EnvCommandBase |
751 | + envcmd.EnvCommandBase |
752 | ServiceName string |
753 | out cmd.Output |
754 | } |
755 | @@ -79,6 +80,10 @@ |
756 | } |
757 | |
758 | func (c *GetConstraintsCommand) Init(args []string) error { |
759 | + err := c.EnvCommandBase.Init() |
760 | + if err != nil { |
761 | + return err |
762 | + } |
763 | if len(args) > 0 { |
764 | if !names.IsService(args[0]) { |
765 | return fmt.Errorf("invalid service name %q", args[0]) |
766 | @@ -129,7 +134,7 @@ |
767 | |
768 | // SetConstraintsCommand shows the constraints for a service or environment. |
769 | type SetConstraintsCommand struct { |
770 | - cmd.EnvCommandBase |
771 | + envcmd.EnvCommandBase |
772 | ServiceName string |
773 | Constraints constraints.Value |
774 | } |
775 | @@ -150,6 +155,10 @@ |
776 | } |
777 | |
778 | func (c *SetConstraintsCommand) Init(args []string) (err error) { |
779 | + err = c.EnvCommandBase.Init() |
780 | + if err != nil { |
781 | + return |
782 | + } |
783 | if c.ServiceName != "" && !names.IsService(c.ServiceName) { |
784 | return fmt.Errorf("invalid service name %q", c.ServiceName) |
785 | } |
786 | |
787 | === modified file 'cmd/juju/debuglog_test.go' |
788 | --- cmd/juju/debuglog_test.go 2013-08-13 07:37:58 +0000 |
789 | +++ cmd/juju/debuglog_test.go 2014-04-01 14:32:48 +0000 |
790 | @@ -36,7 +36,7 @@ |
791 | // debug-log is implemented by invoking juju ssh with the correct arguments. |
792 | // This test helper checks for the expected invocation. |
793 | func (s *DebugLogSuite) assertDebugLogInvokesSSHCommand(c *gc.C, expected string, args ...string) { |
794 | - defer testing.MakeEmptyFakeHome(c).Restore() |
795 | + defer testing.MakeSampleHome(c).Restore() |
796 | debugLogCmd, err := runDebugLog(c, args...) |
797 | c.Assert(err, gc.IsNil) |
798 | debugCmd := debugLogCmd.sshCmd.(*dummySSHCommand) |
799 | @@ -65,7 +65,7 @@ |
800 | } |
801 | |
802 | func (s *DebugLogSuite) TestDebugLogValidation(c *gc.C) { |
803 | - defer testing.MakeEmptyFakeHome(c).Restore() |
804 | + defer testing.MakeSampleHome(c).Restore() |
805 | _, err := runDebugLog(c, "-n", "0") |
806 | c.Assert(err, gc.ErrorMatches, "invalid value \"0\" for flag -n: invalid number of lines") |
807 | _, err = runDebugLog(c, "-n", "-1") |
808 | |
809 | === modified file 'cmd/juju/deploy.go' |
810 | --- cmd/juju/deploy.go 2014-03-31 08:55:49 +0000 |
811 | +++ cmd/juju/deploy.go 2014-04-01 14:32:48 +0000 |
812 | @@ -13,6 +13,7 @@ |
813 | |
814 | "launchpad.net/juju-core/charm" |
815 | "launchpad.net/juju-core/cmd" |
816 | + "launchpad.net/juju-core/cmd/envcmd" |
817 | "launchpad.net/juju-core/constraints" |
818 | "launchpad.net/juju-core/environs" |
819 | "launchpad.net/juju-core/environs/config" |
820 | @@ -24,7 +25,7 @@ |
821 | ) |
822 | |
823 | type DeployCommand struct { |
824 | - cmd.EnvCommandBase |
825 | + envcmd.EnvCommandBase |
826 | UnitCommandBase |
827 | CharmName string |
828 | ServiceName string |
829 | @@ -109,6 +110,10 @@ |
830 | } |
831 | |
832 | func (c *DeployCommand) Init(args []string) error { |
833 | + err := c.EnvCommandBase.Init() |
834 | + if err != nil { |
835 | + return err |
836 | + } |
837 | switch len(args) { |
838 | case 2: |
839 | if !names.IsService(args[1]) { |
840 | |
841 | === modified file 'cmd/juju/destroymachine.go' |
842 | --- cmd/juju/destroymachine.go 2014-02-25 22:19:30 +0000 |
843 | +++ cmd/juju/destroymachine.go 2014-04-01 14:32:48 +0000 |
844 | @@ -9,6 +9,7 @@ |
845 | "launchpad.net/gnuflag" |
846 | |
847 | "launchpad.net/juju-core/cmd" |
848 | + "launchpad.net/juju-core/cmd/envcmd" |
849 | "launchpad.net/juju-core/juju" |
850 | "launchpad.net/juju-core/names" |
851 | "launchpad.net/juju-core/state/api/params" |
852 | @@ -17,7 +18,7 @@ |
853 | |
854 | // DestroyMachineCommand causes an existing machine to be destroyed. |
855 | type DestroyMachineCommand struct { |
856 | - cmd.EnvCommandBase |
857 | + envcmd.EnvCommandBase |
858 | MachineIds []string |
859 | Force bool |
860 | } |
861 | @@ -45,6 +46,10 @@ |
862 | } |
863 | |
864 | func (c *DestroyMachineCommand) Init(args []string) error { |
865 | + err := c.EnvCommandBase.Init() |
866 | + if err != nil { |
867 | + return err |
868 | + } |
869 | if len(args) == 0 { |
870 | return fmt.Errorf("no machines specified") |
871 | } |
872 | |
873 | === modified file 'cmd/juju/destroyrelation.go' |
874 | --- cmd/juju/destroyrelation.go 2013-11-05 04:12:48 +0000 |
875 | +++ cmd/juju/destroyrelation.go 2014-04-01 14:32:48 +0000 |
876 | @@ -7,12 +7,13 @@ |
877 | "fmt" |
878 | |
879 | "launchpad.net/juju-core/cmd" |
880 | + "launchpad.net/juju-core/cmd/envcmd" |
881 | "launchpad.net/juju-core/juju" |
882 | ) |
883 | |
884 | // DestroyRelationCommand causes an existing service relation to be shut down. |
885 | type DestroyRelationCommand struct { |
886 | - cmd.EnvCommandBase |
887 | + envcmd.EnvCommandBase |
888 | Endpoints []string |
889 | } |
890 | |
891 | @@ -26,6 +27,10 @@ |
892 | } |
893 | |
894 | func (c *DestroyRelationCommand) Init(args []string) error { |
895 | + err := c.EnvCommandBase.Init() |
896 | + if err != nil { |
897 | + return err |
898 | + } |
899 | if len(args) != 2 { |
900 | return fmt.Errorf("a relation must involve two services") |
901 | } |
902 | |
903 | === modified file 'cmd/juju/destroyservice.go' |
904 | --- cmd/juju/destroyservice.go 2014-02-25 22:19:30 +0000 |
905 | +++ cmd/juju/destroyservice.go 2014-04-01 14:32:48 +0000 |
906 | @@ -7,13 +7,14 @@ |
907 | "fmt" |
908 | |
909 | "launchpad.net/juju-core/cmd" |
910 | + "launchpad.net/juju-core/cmd/envcmd" |
911 | "launchpad.net/juju-core/juju" |
912 | "launchpad.net/juju-core/names" |
913 | ) |
914 | |
915 | // DestroyServiceCommand causes an existing service to be destroyed. |
916 | type DestroyServiceCommand struct { |
917 | - cmd.EnvCommandBase |
918 | + envcmd.EnvCommandBase |
919 | ServiceName string |
920 | } |
921 | |
922 | @@ -28,6 +29,10 @@ |
923 | } |
924 | |
925 | func (c *DestroyServiceCommand) Init(args []string) error { |
926 | + err := c.EnvCommandBase.Init() |
927 | + if err != nil { |
928 | + return err |
929 | + } |
930 | if len(args) == 0 { |
931 | return fmt.Errorf("no service specified") |
932 | } |
933 | |
934 | === modified file 'cmd/juju/destroyunit.go' |
935 | --- cmd/juju/destroyunit.go 2013-12-04 15:34:47 +0000 |
936 | +++ cmd/juju/destroyunit.go 2014-04-01 14:32:48 +0000 |
937 | @@ -8,13 +8,14 @@ |
938 | "fmt" |
939 | |
940 | "launchpad.net/juju-core/cmd" |
941 | + "launchpad.net/juju-core/cmd/envcmd" |
942 | "launchpad.net/juju-core/juju" |
943 | "launchpad.net/juju-core/names" |
944 | ) |
945 | |
946 | // DestroyUnitCommand is responsible for destroying service units. |
947 | type DestroyUnitCommand struct { |
948 | - cmd.EnvCommandBase |
949 | + envcmd.EnvCommandBase |
950 | UnitNames []string |
951 | } |
952 | |
953 | @@ -28,6 +29,10 @@ |
954 | } |
955 | |
956 | func (c *DestroyUnitCommand) Init(args []string) error { |
957 | + err := c.EnvCommandBase.Init() |
958 | + if err != nil { |
959 | + return err |
960 | + } |
961 | c.UnitNames = args |
962 | if len(c.UnitNames) == 0 { |
963 | return errors.New("no units specified") |
964 | |
965 | === modified file 'cmd/juju/endpoint.go' |
966 | --- cmd/juju/endpoint.go 2013-09-30 17:23:28 +0000 |
967 | +++ cmd/juju/endpoint.go 2014-04-01 14:32:48 +0000 |
968 | @@ -7,13 +7,14 @@ |
969 | "launchpad.net/gnuflag" |
970 | |
971 | "launchpad.net/juju-core/cmd" |
972 | + "launchpad.net/juju-core/cmd/envcmd" |
973 | "launchpad.net/juju-core/environs" |
974 | "launchpad.net/juju-core/environs/configstore" |
975 | ) |
976 | |
977 | // EndpointCommand returns the API endpoints |
978 | type EndpointCommand struct { |
979 | - cmd.EnvCommandBase |
980 | + envcmd.EnvCommandBase |
981 | out cmd.Output |
982 | } |
983 | |
984 | @@ -37,6 +38,10 @@ |
985 | } |
986 | |
987 | func (c *EndpointCommand) Init(args []string) error { |
988 | + err := c.EnvCommandBase.Init() |
989 | + if err != nil { |
990 | + return err |
991 | + } |
992 | return cmd.CheckEmpty(args) |
993 | } |
994 | |
995 | |
996 | === modified file 'cmd/juju/ensureavailability.go' |
997 | --- cmd/juju/ensureavailability.go 2014-03-28 09:55:10 +0000 |
998 | +++ cmd/juju/ensureavailability.go 2014-04-01 14:32:48 +0000 |
999 | @@ -9,12 +9,13 @@ |
1000 | "launchpad.net/gnuflag" |
1001 | |
1002 | "launchpad.net/juju-core/cmd" |
1003 | + "launchpad.net/juju-core/cmd/envcmd" |
1004 | "launchpad.net/juju-core/constraints" |
1005 | "launchpad.net/juju-core/juju" |
1006 | ) |
1007 | |
1008 | type EnsureAvailabilityCommand struct { |
1009 | - cmd.EnvCommandBase |
1010 | + envcmd.EnvCommandBase |
1011 | NumStateServers int |
1012 | // If specified, use this series for newly created machines, |
1013 | // else use the environment's default-series |
1014 | @@ -63,6 +64,10 @@ |
1015 | } |
1016 | |
1017 | func (c *EnsureAvailabilityCommand) Init(args []string) error { |
1018 | + err := c.EnvCommandBase.Init() |
1019 | + if err != nil { |
1020 | + return err |
1021 | + } |
1022 | if c.NumStateServers%2 != 1 || c.NumStateServers <= 0 { |
1023 | return fmt.Errorf("must specify a number of state servers odd and greater than zero") |
1024 | } |
1025 | |
1026 | === modified file 'cmd/juju/environment.go' |
1027 | --- cmd/juju/environment.go 2014-03-26 06:32:05 +0000 |
1028 | +++ cmd/juju/environment.go 2014-04-01 14:32:48 +0000 |
1029 | @@ -10,6 +10,7 @@ |
1030 | "launchpad.net/gnuflag" |
1031 | |
1032 | "launchpad.net/juju-core/cmd" |
1033 | + "launchpad.net/juju-core/cmd/envcmd" |
1034 | "launchpad.net/juju-core/juju" |
1035 | "launchpad.net/juju-core/state/api/params" |
1036 | ) |
1037 | @@ -17,7 +18,7 @@ |
1038 | // GetEnvironmentCommand is able to output either the entire environment or |
1039 | // the requested value in a format of the user's choosing. |
1040 | type GetEnvironmentCommand struct { |
1041 | - cmd.EnvCommandBase |
1042 | + envcmd.EnvCommandBase |
1043 | key string |
1044 | out cmd.Output |
1045 | } |
1046 | @@ -50,6 +51,10 @@ |
1047 | } |
1048 | |
1049 | func (c *GetEnvironmentCommand) Init(args []string) (err error) { |
1050 | + err = c.EnvCommandBase.Init() |
1051 | + if err != nil { |
1052 | + return |
1053 | + } |
1054 | c.key, err = cmd.ZeroOrOneArgs(args) |
1055 | return |
1056 | } |
1057 | @@ -105,7 +110,7 @@ |
1058 | |
1059 | // SetEnvironment |
1060 | type SetEnvironmentCommand struct { |
1061 | - cmd.EnvCommandBase |
1062 | + envcmd.EnvCommandBase |
1063 | values attributes |
1064 | } |
1065 | |
1066 | @@ -127,6 +132,10 @@ |
1067 | // SetFlags handled entirely by cmd.EnvCommandBase |
1068 | |
1069 | func (c *SetEnvironmentCommand) Init(args []string) (err error) { |
1070 | + err = c.EnvCommandBase.Init() |
1071 | + if err != nil { |
1072 | + return |
1073 | + } |
1074 | if len(args) == 0 { |
1075 | return fmt.Errorf("No key, value pairs specified") |
1076 | } |
1077 | @@ -184,7 +193,7 @@ |
1078 | |
1079 | // UnsetEnvironment |
1080 | type UnsetEnvironmentCommand struct { |
1081 | - cmd.EnvCommandBase |
1082 | + envcmd.EnvCommandBase |
1083 | keys []string |
1084 | } |
1085 | |
1086 | @@ -208,6 +217,10 @@ |
1087 | } |
1088 | |
1089 | func (c *UnsetEnvironmentCommand) Init(args []string) (err error) { |
1090 | + err = c.EnvCommandBase.Init() |
1091 | + if err != nil { |
1092 | + return |
1093 | + } |
1094 | if len(args) == 0 { |
1095 | return fmt.Errorf("No keys specified") |
1096 | } |
1097 | |
1098 | === modified file 'cmd/juju/expose.go' |
1099 | --- cmd/juju/expose.go 2013-11-01 09:09:43 +0000 |
1100 | +++ cmd/juju/expose.go 2014-04-01 14:32:48 +0000 |
1101 | @@ -7,12 +7,13 @@ |
1102 | "errors" |
1103 | |
1104 | "launchpad.net/juju-core/cmd" |
1105 | + "launchpad.net/juju-core/cmd/envcmd" |
1106 | "launchpad.net/juju-core/juju" |
1107 | ) |
1108 | |
1109 | // ExposeCommand is responsible exposing services. |
1110 | type ExposeCommand struct { |
1111 | - cmd.EnvCommandBase |
1112 | + envcmd.EnvCommandBase |
1113 | ServiceName string |
1114 | } |
1115 | |
1116 | @@ -25,6 +26,10 @@ |
1117 | } |
1118 | |
1119 | func (c *ExposeCommand) Init(args []string) error { |
1120 | + err := c.EnvCommandBase.Init() |
1121 | + if err != nil { |
1122 | + return err |
1123 | + } |
1124 | if len(args) == 0 { |
1125 | return errors.New("no service name specified") |
1126 | } |
1127 | |
1128 | === modified file 'cmd/juju/get.go' |
1129 | --- cmd/juju/get.go 2013-09-30 20:58:11 +0000 |
1130 | +++ cmd/juju/get.go 2014-04-01 14:32:48 +0000 |
1131 | @@ -9,12 +9,13 @@ |
1132 | "launchpad.net/gnuflag" |
1133 | |
1134 | "launchpad.net/juju-core/cmd" |
1135 | + "launchpad.net/juju-core/cmd/envcmd" |
1136 | "launchpad.net/juju-core/juju" |
1137 | ) |
1138 | |
1139 | // GetCommand retrieves the configuration of a service. |
1140 | type GetCommand struct { |
1141 | - cmd.EnvCommandBase |
1142 | + envcmd.EnvCommandBase |
1143 | ServiceName string |
1144 | out cmd.Output |
1145 | } |
1146 | @@ -36,6 +37,10 @@ |
1147 | } |
1148 | |
1149 | func (c *GetCommand) Init(args []string) error { |
1150 | + err := c.EnvCommandBase.Init() |
1151 | + if err != nil { |
1152 | + return err |
1153 | + } |
1154 | // TODO(dfc) add --schema-only |
1155 | if len(args) == 0 { |
1156 | return errors.New("no service name specified") |
1157 | |
1158 | === modified file 'cmd/juju/plugin.go' |
1159 | --- cmd/juju/plugin.go 2014-02-17 12:57:06 +0000 |
1160 | +++ cmd/juju/plugin.go 2014-04-01 14:32:48 +0000 |
1161 | @@ -16,6 +16,7 @@ |
1162 | "launchpad.net/gnuflag" |
1163 | |
1164 | "launchpad.net/juju-core/cmd" |
1165 | + "launchpad.net/juju-core/cmd/envcmd" |
1166 | "launchpad.net/juju-core/juju/osenv" |
1167 | "launchpad.net/juju-core/log" |
1168 | ) |
1169 | @@ -72,7 +73,7 @@ |
1170 | } |
1171 | |
1172 | type PluginCommand struct { |
1173 | - cmd.EnvCommandBase |
1174 | + envcmd.EnvCommandBase |
1175 | name string |
1176 | args []string |
1177 | } |
1178 | @@ -85,7 +86,7 @@ |
1179 | |
1180 | func (c *PluginCommand) Init(args []string) error { |
1181 | c.args = args |
1182 | - return nil |
1183 | + return c.EnvCommandBase.Init() |
1184 | } |
1185 | |
1186 | func (c *PluginCommand) SetFlags(f *gnuflag.FlagSet) { |
1187 | |
1188 | === modified file 'cmd/juju/publish.go' |
1189 | --- cmd/juju/publish.go 2014-03-18 05:08:25 +0000 |
1190 | +++ cmd/juju/publish.go 2014-04-01 14:32:48 +0000 |
1191 | @@ -14,11 +14,12 @@ |
1192 | "launchpad.net/juju-core/bzr" |
1193 | "launchpad.net/juju-core/charm" |
1194 | "launchpad.net/juju-core/cmd" |
1195 | + "launchpad.net/juju-core/cmd/envcmd" |
1196 | "launchpad.net/juju-core/log" |
1197 | ) |
1198 | |
1199 | type PublishCommand struct { |
1200 | - cmd.EnvCommandBase |
1201 | + envcmd.EnvCommandBase |
1202 | URL string |
1203 | CharmPath string |
1204 | |
1205 | @@ -60,6 +61,10 @@ |
1206 | } |
1207 | |
1208 | func (c *PublishCommand) Init(args []string) error { |
1209 | + err := c.EnvCommandBase.Init() |
1210 | + if err != nil { |
1211 | + return err |
1212 | + } |
1213 | if len(args) == 0 { |
1214 | return nil |
1215 | } |
1216 | |
1217 | === modified file 'cmd/juju/publish_test.go' |
1218 | --- cmd/juju/publish_test.go 2014-03-18 05:08:25 +0000 |
1219 | +++ cmd/juju/publish_test.go 2014-04-01 14:32:48 +0000 |
1220 | @@ -75,11 +75,9 @@ |
1221 | func (s *PublishSuite) SetUpTest(c *gc.C) { |
1222 | s.LoggingSuite.SetUpTest(c) |
1223 | s.HTTPSuite.SetUpTest(c) |
1224 | - s.home = testing.MakeFakeHomeWithFiles(c, []testing.TestFile{ |
1225 | - { |
1226 | - Name: ".bazaar/bazaar.conf", |
1227 | - Data: "[DEFAULT]\nemail = Test <testing@testing.invalid>\n", |
1228 | - }, |
1229 | + s.home = testing.MakeSampleHome(c, testing.TestFile{ |
1230 | + Name: ".bazaar/bazaar.conf", |
1231 | + Data: "[DEFAULT]\nemail = Test <testing@testing.invalid>\n", |
1232 | }) |
1233 | |
1234 | s.dir = c.MkDir() |
1235 | |
1236 | === added file 'cmd/juju/removeuser.go' |
1237 | --- cmd/juju/removeuser.go 1970-01-01 00:00:00 +0000 |
1238 | +++ cmd/juju/removeuser.go 2014-04-01 14:32:48 +0000 |
1239 | @@ -0,0 +1,55 @@ |
1240 | +// Copyright 2014 Canonical Ltd. |
1241 | +// Licensed under the AGPLv3, see LICENCE file for details. |
1242 | + |
1243 | +package main |
1244 | + |
1245 | +import ( |
1246 | + "errors" |
1247 | + |
1248 | + "launchpad.net/juju-core/cmd" |
1249 | + "launchpad.net/juju-core/cmd/envcmd" |
1250 | + "launchpad.net/juju-core/juju" |
1251 | +) |
1252 | + |
1253 | +const removeUserDoc = ` |
1254 | +Remove users from an existing environment |
1255 | + |
1256 | +Examples: |
1257 | + juju remove-user foobar |
1258 | +` |
1259 | + |
1260 | +type RemoveUserCommand struct { |
1261 | + envcmd.EnvCommandBase |
1262 | + User string |
1263 | +} |
1264 | + |
1265 | +func (c *RemoveUserCommand) Info() *cmd.Info { |
1266 | + return &cmd.Info{ |
1267 | + Name: "remove-user", |
1268 | + Args: "<username>", |
1269 | + Purpose: "removes a user", |
1270 | + Doc: removeUserDoc, |
1271 | + } |
1272 | +} |
1273 | + |
1274 | +func (c *RemoveUserCommand) Init(args []string) error { |
1275 | + err := c.EnvCommandBase.Init() |
1276 | + if err != nil { |
1277 | + return err |
1278 | + } |
1279 | + if len(args) == 0 { |
1280 | + return errors.New("no username supplied") |
1281 | + } |
1282 | + c.User = args[0] |
1283 | + |
1284 | + return cmd.CheckEmpty(args[1:]) |
1285 | +} |
1286 | + |
1287 | +func (c *RemoveUserCommand) Run(_ *cmd.Context) error { |
1288 | + client, err := juju.NewUserManagerClient(c.EnvName) |
1289 | + if err != nil { |
1290 | + return err |
1291 | + } |
1292 | + defer client.Close() |
1293 | + return client.RemoveUser(c.User) |
1294 | +} |
1295 | |
1296 | === added file 'cmd/juju/removeuser_test.go' |
1297 | --- cmd/juju/removeuser_test.go 1970-01-01 00:00:00 +0000 |
1298 | +++ cmd/juju/removeuser_test.go 2014-04-01 14:32:48 +0000 |
1299 | @@ -0,0 +1,35 @@ |
1300 | +// Copyright 2014 Canonical Ltd. |
1301 | +// Licensed under the AGPLv3, see LICENCE file for details. |
1302 | + |
1303 | +package main |
1304 | + |
1305 | +import ( |
1306 | + gc "launchpad.net/gocheck" |
1307 | + |
1308 | + jujutesting "launchpad.net/juju-core/juju/testing" |
1309 | + "launchpad.net/juju-core/testing" |
1310 | +) |
1311 | + |
1312 | +type RemoveUserSuite struct { |
1313 | + jujutesting.RepoSuite |
1314 | +} |
1315 | + |
1316 | +var _ = gc.Suite(&RemoveUserSuite{}) |
1317 | + |
1318 | +func (s *RemoveUserSuite) TestRemoveUser(c *gc.C) { |
1319 | + _, err := testing.RunCommand(c, &AddUserCommand{}, []string{"foobar", "password"}) |
1320 | + c.Assert(err, gc.IsNil) |
1321 | + |
1322 | + _, err = testing.RunCommand(c, &RemoveUserCommand{}, []string{"foobar"}) |
1323 | + c.Assert(err, gc.IsNil) |
1324 | +} |
1325 | + |
1326 | +func (s *RemoveUserSuite) TestTooManyArgs(c *gc.C) { |
1327 | + _, err := testing.RunCommand(c, &RemoveUserCommand{}, []string{"foobar", "password"}) |
1328 | + c.Assert(err, gc.ErrorMatches, `unrecognized args: \["password"\]`) |
1329 | +} |
1330 | + |
1331 | +func (s *RemoveUserSuite) TestNotEnoughArgs(c *gc.C) { |
1332 | + _, err := testing.RunCommand(c, &RemoveUserCommand{}, []string{}) |
1333 | + c.Assert(err, gc.ErrorMatches, `no username supplied`) |
1334 | +} |
1335 | |
1336 | === modified file 'cmd/juju/resolved.go' |
1337 | --- cmd/juju/resolved.go 2013-11-01 09:26:22 +0000 |
1338 | +++ cmd/juju/resolved.go 2014-04-01 14:32:48 +0000 |
1339 | @@ -9,13 +9,14 @@ |
1340 | "launchpad.net/gnuflag" |
1341 | |
1342 | "launchpad.net/juju-core/cmd" |
1343 | + "launchpad.net/juju-core/cmd/envcmd" |
1344 | "launchpad.net/juju-core/juju" |
1345 | "launchpad.net/juju-core/names" |
1346 | ) |
1347 | |
1348 | // ResolvedCommand marks a unit in an error state as ready to continue. |
1349 | type ResolvedCommand struct { |
1350 | - cmd.EnvCommandBase |
1351 | + envcmd.EnvCommandBase |
1352 | UnitName string |
1353 | Retry bool |
1354 | } |
1355 | @@ -35,6 +36,10 @@ |
1356 | } |
1357 | |
1358 | func (c *ResolvedCommand) Init(args []string) error { |
1359 | + err := c.EnvCommandBase.Init() |
1360 | + if err != nil { |
1361 | + return err |
1362 | + } |
1363 | if len(args) > 0 { |
1364 | c.UnitName = args[0] |
1365 | if !names.IsUnit(c.UnitName) { |
1366 | |
1367 | === modified file 'cmd/juju/retryprovisioning.go' |
1368 | --- cmd/juju/retryprovisioning.go 2014-03-26 12:43:56 +0000 |
1369 | +++ cmd/juju/retryprovisioning.go 2014-04-01 14:32:48 +0000 |
1370 | @@ -7,6 +7,7 @@ |
1371 | "fmt" |
1372 | |
1373 | "launchpad.net/juju-core/cmd" |
1374 | + "launchpad.net/juju-core/cmd/envcmd" |
1375 | "launchpad.net/juju-core/juju" |
1376 | "launchpad.net/juju-core/names" |
1377 | ) |
1378 | @@ -14,7 +15,7 @@ |
1379 | // RetryProvisioningCommand updates machines' error status to tell |
1380 | // the provisoner that it should try to re-provision the machine. |
1381 | type RetryProvisioningCommand struct { |
1382 | - cmd.EnvCommandBase |
1383 | + envcmd.EnvCommandBase |
1384 | Machines []string |
1385 | } |
1386 | |
1387 | |
1388 | === modified file 'cmd/juju/run.go' |
1389 | --- cmd/juju/run.go 2014-01-12 20:28:39 +0000 |
1390 | +++ cmd/juju/run.go 2014-04-01 14:32:48 +0000 |
1391 | @@ -14,6 +14,7 @@ |
1392 | "launchpad.net/gnuflag" |
1393 | |
1394 | "launchpad.net/juju-core/cmd" |
1395 | + "launchpad.net/juju-core/cmd/envcmd" |
1396 | "launchpad.net/juju-core/juju" |
1397 | "launchpad.net/juju-core/names" |
1398 | "launchpad.net/juju-core/state/api/params" |
1399 | @@ -21,7 +22,7 @@ |
1400 | |
1401 | // RunCommand is responsible for running arbitrary commands on remote machines. |
1402 | type RunCommand struct { |
1403 | - cmd.EnvCommandBase |
1404 | + envcmd.EnvCommandBase |
1405 | out cmd.Output |
1406 | all bool |
1407 | timeout time.Duration |
1408 | @@ -79,6 +80,10 @@ |
1409 | } |
1410 | |
1411 | func (c *RunCommand) Init(args []string) error { |
1412 | + err := c.EnvCommandBase.Init() |
1413 | + if err != nil { |
1414 | + return err |
1415 | + } |
1416 | if len(args) == 0 { |
1417 | return errors.New("no commands specified") |
1418 | } |
1419 | |
1420 | === modified file 'cmd/juju/run_test.go' |
1421 | --- cmd/juju/run_test.go 2014-03-13 07:54:56 +0000 |
1422 | +++ cmd/juju/run_test.go 2014-04-01 14:32:48 +0000 |
1423 | @@ -321,7 +321,7 @@ |
1424 | message: "smart (default)", |
1425 | stdout: "stdout\n", |
1426 | stderr: "stderr\n", |
1427 | - errorMatch: "rc: 42", |
1428 | + errorMatch: "subprocess encountered error code 42", |
1429 | }, { |
1430 | message: "yaml output", |
1431 | format: "yaml", |
1432 | |
1433 | === modified file 'cmd/juju/set.go' |
1434 | --- cmd/juju/set.go 2013-12-17 18:21:26 +0000 |
1435 | +++ cmd/juju/set.go 2014-04-01 14:32:48 +0000 |
1436 | @@ -11,13 +11,14 @@ |
1437 | "launchpad.net/gnuflag" |
1438 | |
1439 | "launchpad.net/juju-core/cmd" |
1440 | + "launchpad.net/juju-core/cmd/envcmd" |
1441 | "launchpad.net/juju-core/juju" |
1442 | "launchpad.net/juju-core/state/api/params" |
1443 | ) |
1444 | |
1445 | // SetCommand updates the configuration of a service. |
1446 | type SetCommand struct { |
1447 | - cmd.EnvCommandBase |
1448 | + envcmd.EnvCommandBase |
1449 | ServiceName string |
1450 | SettingsStrings map[string]string |
1451 | SettingsYAML cmd.FileVar |
1452 | @@ -44,6 +45,10 @@ |
1453 | } |
1454 | |
1455 | func (c *SetCommand) Init(args []string) error { |
1456 | + err := c.EnvCommandBase.Init() |
1457 | + if err != nil { |
1458 | + return err |
1459 | + } |
1460 | if len(args) == 0 || len(strings.Split(args[0], "=")) > 1 { |
1461 | return errors.New("no service name specified") |
1462 | } |
1463 | |
1464 | === modified file 'cmd/juju/ssh.go' |
1465 | --- cmd/juju/ssh.go 2014-03-20 02:30:15 +0000 |
1466 | +++ cmd/juju/ssh.go 2014-04-01 14:32:48 +0000 |
1467 | @@ -9,6 +9,7 @@ |
1468 | "time" |
1469 | |
1470 | "launchpad.net/juju-core/cmd" |
1471 | + "launchpad.net/juju-core/cmd/envcmd" |
1472 | "launchpad.net/juju-core/instance" |
1473 | "launchpad.net/juju-core/juju" |
1474 | "launchpad.net/juju-core/names" |
1475 | @@ -25,7 +26,7 @@ |
1476 | |
1477 | // SSHCommon provides common methods for SSHCommand, SCPCommand and DebugHooksCommand. |
1478 | type SSHCommon struct { |
1479 | - cmd.EnvCommandBase |
1480 | + envcmd.EnvCommandBase |
1481 | Target string |
1482 | Args []string |
1483 | apiClient *api.Client |
1484 | @@ -68,6 +69,10 @@ |
1485 | } |
1486 | |
1487 | func (c *SSHCommand) Init(args []string) error { |
1488 | + err := c.EnvCommandBase.Init() |
1489 | + if err != nil { |
1490 | + return err |
1491 | + } |
1492 | if len(args) == 0 { |
1493 | return errors.New("no target name specified") |
1494 | } |
1495 | |
1496 | === modified file 'cmd/juju/status.go' |
1497 | --- cmd/juju/status.go 2014-03-26 12:42:03 +0000 |
1498 | +++ cmd/juju/status.go 2014-04-01 14:32:48 +0000 |
1499 | @@ -10,6 +10,7 @@ |
1500 | "launchpad.net/gnuflag" |
1501 | |
1502 | "launchpad.net/juju-core/cmd" |
1503 | + "launchpad.net/juju-core/cmd/envcmd" |
1504 | "launchpad.net/juju-core/instance" |
1505 | "launchpad.net/juju-core/juju" |
1506 | "launchpad.net/juju-core/state/api" |
1507 | @@ -18,7 +19,7 @@ |
1508 | ) |
1509 | |
1510 | type StatusCommand struct { |
1511 | - cmd.EnvCommandBase |
1512 | + envcmd.EnvCommandBase |
1513 | out cmd.Output |
1514 | patterns []string |
1515 | } |
1516 | @@ -57,7 +58,7 @@ |
1517 | |
1518 | func (c *StatusCommand) Init(args []string) error { |
1519 | c.patterns = args |
1520 | - return nil |
1521 | + return c.EnvCommandBase.Init() |
1522 | } |
1523 | |
1524 | var connectionError = `Unable to connect to environment "%s". |
1525 | |
1526 | === modified file 'cmd/juju/switch.go' |
1527 | --- cmd/juju/switch.go 2014-01-29 15:57:25 +0000 |
1528 | +++ cmd/juju/switch.go 2014-04-01 14:32:48 +0000 |
1529 | @@ -12,6 +12,7 @@ |
1530 | "launchpad.net/gnuflag" |
1531 | |
1532 | "launchpad.net/juju-core/cmd" |
1533 | + "launchpad.net/juju-core/cmd/envcmd" |
1534 | "launchpad.net/juju-core/environs" |
1535 | ) |
1536 | |
1537 | @@ -96,7 +97,7 @@ |
1538 | } |
1539 | } |
1540 | |
1541 | - currentEnv := cmd.ReadCurrentEnvironment() |
1542 | + currentEnv := envcmd.ReadCurrentEnvironment() |
1543 | if currentEnv == "" { |
1544 | currentEnv = environments.Default |
1545 | } |
1546 | @@ -114,7 +115,7 @@ |
1547 | if !validEnvironmentName(c.EnvName, names) { |
1548 | return fmt.Errorf("%q is not a name of an existing defined environment", c.EnvName) |
1549 | } |
1550 | - if err := cmd.WriteCurrentEnvironment(c.EnvName); err != nil { |
1551 | + if err := envcmd.WriteCurrentEnvironment(c.EnvName); err != nil { |
1552 | return err |
1553 | } |
1554 | if currentEnv == "" { |
1555 | |
1556 | === modified file 'cmd/juju/switch_test.go' |
1557 | --- cmd/juju/switch_test.go 2014-01-29 13:46:37 +0000 |
1558 | +++ cmd/juju/switch_test.go 2014-04-01 14:32:48 +0000 |
1559 | @@ -8,7 +8,7 @@ |
1560 | |
1561 | gc "launchpad.net/gocheck" |
1562 | |
1563 | - "launchpad.net/juju-core/cmd" |
1564 | + "launchpad.net/juju-core/cmd/envcmd" |
1565 | _ "launchpad.net/juju-core/juju" |
1566 | "launchpad.net/juju-core/testing" |
1567 | ) |
1568 | @@ -69,7 +69,7 @@ |
1569 | context, err := testing.RunCommand(c, &SwitchCommand{}, []string{"erewhemos-2"}) |
1570 | c.Assert(err, gc.IsNil) |
1571 | c.Assert(testing.Stdout(context), gc.Equals, "erewhemos -> erewhemos-2\n") |
1572 | - c.Assert(cmd.ReadCurrentEnvironment(), gc.Equals, "erewhemos-2") |
1573 | + c.Assert(envcmd.ReadCurrentEnvironment(), gc.Equals, "erewhemos-2") |
1574 | } |
1575 | |
1576 | func (*SwitchSimpleSuite) TestSettingToUnknown(c *gc.C) { |
1577 | |
1578 | === modified file 'cmd/juju/synctools.go' |
1579 | --- cmd/juju/synctools.go 2014-03-10 00:45:41 +0000 |
1580 | +++ cmd/juju/synctools.go 2014-04-01 14:32:48 +0000 |
1581 | @@ -8,6 +8,7 @@ |
1582 | "launchpad.net/gnuflag" |
1583 | |
1584 | "launchpad.net/juju-core/cmd" |
1585 | + "launchpad.net/juju-core/cmd/envcmd" |
1586 | "launchpad.net/juju-core/environs/filestorage" |
1587 | "launchpad.net/juju-core/environs/sync" |
1588 | "launchpad.net/juju-core/version" |
1589 | @@ -18,7 +19,7 @@ |
1590 | // SyncToolsCommand copies all the tools from the us-east-1 bucket to the local |
1591 | // bucket. |
1592 | type SyncToolsCommand struct { |
1593 | - cmd.EnvCommandBase |
1594 | + envcmd.EnvCommandBase |
1595 | allVersions bool |
1596 | versionStr string |
1597 | majorVersion int |
1598 | @@ -63,6 +64,10 @@ |
1599 | } |
1600 | |
1601 | func (c *SyncToolsCommand) Init(args []string) error { |
1602 | + err := c.EnvCommandBase.Init() |
1603 | + if err != nil { |
1604 | + return err |
1605 | + } |
1606 | if c.destination != "" { |
1607 | // Override localDir with destination as localDir now replaces destination |
1608 | c.localDir = c.destination |
1609 | |
1610 | === modified file 'cmd/juju/unexpose.go' |
1611 | --- cmd/juju/unexpose.go 2013-11-01 09:09:43 +0000 |
1612 | +++ cmd/juju/unexpose.go 2014-04-01 14:32:48 +0000 |
1613 | @@ -7,12 +7,13 @@ |
1614 | "errors" |
1615 | |
1616 | "launchpad.net/juju-core/cmd" |
1617 | + "launchpad.net/juju-core/cmd/envcmd" |
1618 | "launchpad.net/juju-core/juju" |
1619 | ) |
1620 | |
1621 | // UnexposeCommand is responsible exposing services. |
1622 | type UnexposeCommand struct { |
1623 | - cmd.EnvCommandBase |
1624 | + envcmd.EnvCommandBase |
1625 | ServiceName string |
1626 | } |
1627 | |
1628 | @@ -25,6 +26,10 @@ |
1629 | } |
1630 | |
1631 | func (c *UnexposeCommand) Init(args []string) error { |
1632 | + err := c.EnvCommandBase.Init() |
1633 | + if err != nil { |
1634 | + return err |
1635 | + } |
1636 | if len(args) == 0 { |
1637 | return errors.New("no service name specified") |
1638 | } |
1639 | |
1640 | === modified file 'cmd/juju/unset.go' |
1641 | --- cmd/juju/unset.go 2013-12-17 18:21:26 +0000 |
1642 | +++ cmd/juju/unset.go 2014-04-01 14:32:48 +0000 |
1643 | @@ -10,6 +10,7 @@ |
1644 | |
1645 | "launchpad.net/juju-core/charm" |
1646 | "launchpad.net/juju-core/cmd" |
1647 | + "launchpad.net/juju-core/cmd/envcmd" |
1648 | "launchpad.net/juju-core/juju" |
1649 | "launchpad.net/juju-core/state/api/params" |
1650 | ) |
1651 | @@ -17,7 +18,7 @@ |
1652 | // UnsetCommand sets configuration values of a service back |
1653 | // to their default. |
1654 | type UnsetCommand struct { |
1655 | - cmd.EnvCommandBase |
1656 | + envcmd.EnvCommandBase |
1657 | ServiceName string |
1658 | Options []string |
1659 | } |
1660 | @@ -42,6 +43,10 @@ |
1661 | } |
1662 | |
1663 | func (c *UnsetCommand) Init(args []string) error { |
1664 | + err := c.EnvCommandBase.Init() |
1665 | + if err != nil { |
1666 | + return err |
1667 | + } |
1668 | if len(args) == 0 { |
1669 | return errors.New("no service name specified") |
1670 | } |
1671 | |
1672 | === modified file 'cmd/juju/upgradecharm.go' |
1673 | --- cmd/juju/upgradecharm.go 2014-03-18 05:08:25 +0000 |
1674 | +++ cmd/juju/upgradecharm.go 2014-04-01 14:32:48 +0000 |
1675 | @@ -12,6 +12,7 @@ |
1676 | |
1677 | "launchpad.net/juju-core/charm" |
1678 | "launchpad.net/juju-core/cmd" |
1679 | + "launchpad.net/juju-core/cmd/envcmd" |
1680 | "launchpad.net/juju-core/environs/config" |
1681 | "launchpad.net/juju-core/juju" |
1682 | "launchpad.net/juju-core/names" |
1683 | @@ -20,7 +21,7 @@ |
1684 | |
1685 | // UpgradeCharm is responsible for upgrading a service's charm. |
1686 | type UpgradeCharmCommand struct { |
1687 | - cmd.EnvCommandBase |
1688 | + envcmd.EnvCommandBase |
1689 | ServiceName string |
1690 | Force bool |
1691 | RepoPath string // defaults to JUJU_REPOSITORY |
1692 | @@ -84,6 +85,10 @@ |
1693 | } |
1694 | |
1695 | func (c *UpgradeCharmCommand) Init(args []string) error { |
1696 | + err := c.EnvCommandBase.Init() |
1697 | + if err != nil { |
1698 | + return err |
1699 | + } |
1700 | switch len(args) { |
1701 | case 1: |
1702 | if !names.IsService(args[0]) { |
1703 | |
1704 | === modified file 'cmd/juju/upgradejuju.go' |
1705 | --- cmd/juju/upgradejuju.go 2014-03-18 23:44:18 +0000 |
1706 | +++ cmd/juju/upgradejuju.go 2014-04-01 14:32:48 +0000 |
1707 | @@ -12,6 +12,7 @@ |
1708 | "launchpad.net/gnuflag" |
1709 | |
1710 | "launchpad.net/juju-core/cmd" |
1711 | + "launchpad.net/juju-core/cmd/envcmd" |
1712 | "launchpad.net/juju-core/environs" |
1713 | "launchpad.net/juju-core/environs/bootstrap" |
1714 | "launchpad.net/juju-core/environs/config" |
1715 | @@ -28,7 +29,7 @@ |
1716 | |
1717 | // UpgradeJujuCommand upgrades the agents in a juju installation. |
1718 | type UpgradeJujuCommand struct { |
1719 | - cmd.EnvCommandBase |
1720 | + envcmd.EnvCommandBase |
1721 | vers string |
1722 | Version version.Number |
1723 | UploadTools bool |
1724 | @@ -84,6 +85,10 @@ |
1725 | } |
1726 | |
1727 | func (c *UpgradeJujuCommand) Init(args []string) error { |
1728 | + err := c.EnvCommandBase.Init() |
1729 | + if err != nil { |
1730 | + return err |
1731 | + } |
1732 | if c.vers != "" { |
1733 | vers, err := version.Parse(c.vers) |
1734 | if err != nil { |
1735 | |
1736 | === modified file 'cmd/jujud/run_test.go' |
1737 | --- cmd/jujud/run_test.go 2014-03-13 07:54:56 +0000 |
1738 | +++ cmd/jujud/run_test.go 2014-04-01 14:32:48 +0000 |
1739 | @@ -105,7 +105,7 @@ |
1740 | go func() { |
1741 | ctx, err := testing.RunCommand(c, &RunCommand{}, params) |
1742 | c.Assert(err, jc.Satisfies, cmd.IsRcPassthroughError) |
1743 | - c.Assert(err, gc.ErrorMatches, "rc: 0") |
1744 | + c.Assert(err, gc.ErrorMatches, "subprocess encountered error code 0") |
1745 | resultChannel <- ctx |
1746 | close(resultChannel) |
1747 | }() |
1748 | @@ -118,7 +118,7 @@ |
1749 | |
1750 | ctx, err := testing.RunCommand(c, &RunCommand{}, []string{"--no-context", "echo done"}) |
1751 | c.Assert(err, jc.Satisfies, cmd.IsRcPassthroughError) |
1752 | - c.Assert(err, gc.ErrorMatches, "rc: 0") |
1753 | + c.Assert(err, gc.ErrorMatches, "subprocess encountered error code 0") |
1754 | c.Assert(testing.Stdout(ctx), gc.Equals, "done\n") |
1755 | } |
1756 | |
1757 | @@ -168,7 +168,7 @@ |
1758 | |
1759 | ctx, err := testing.RunCommand(c, &RunCommand{}, []string{"foo", "bar"}) |
1760 | c.Check(cmd.IsRcPassthroughError(err), jc.IsTrue) |
1761 | - c.Assert(err, gc.ErrorMatches, "rc: 42") |
1762 | + c.Assert(err, gc.ErrorMatches, "subprocess encountered error code 42") |
1763 | c.Assert(testing.Stdout(ctx), gc.Equals, "bar stdout") |
1764 | c.Assert(testing.Stderr(ctx), gc.Equals, "bar stderr") |
1765 | } |
1766 | |
1767 | === modified file 'cmd/plugins/juju-metadata/imagemetadata.go' |
1768 | --- cmd/plugins/juju-metadata/imagemetadata.go 2014-03-17 03:45:21 +0000 |
1769 | +++ cmd/plugins/juju-metadata/imagemetadata.go 2014-04-01 14:32:48 +0000 |
1770 | @@ -11,6 +11,7 @@ |
1771 | "launchpad.net/gnuflag" |
1772 | |
1773 | "launchpad.net/juju-core/cmd" |
1774 | + "launchpad.net/juju-core/cmd/envcmd" |
1775 | "launchpad.net/juju-core/environs" |
1776 | "launchpad.net/juju-core/environs/config" |
1777 | "launchpad.net/juju-core/environs/configstore" |
1778 | @@ -23,7 +24,7 @@ |
1779 | |
1780 | // ImageMetadataCommand is used to write out simplestreams image metadata information. |
1781 | type ImageMetadataCommand struct { |
1782 | - cmd.EnvCommandBase |
1783 | + envcmd.EnvCommandBase |
1784 | Dir string |
1785 | Series string |
1786 | Arch string |
1787 | |
1788 | === modified file 'cmd/plugins/juju-metadata/toolsmetadata.go' |
1789 | --- cmd/plugins/juju-metadata/toolsmetadata.go 2014-03-21 03:27:16 +0000 |
1790 | +++ cmd/plugins/juju-metadata/toolsmetadata.go 2014-04-01 14:32:48 +0000 |
1791 | @@ -10,6 +10,7 @@ |
1792 | "launchpad.net/gnuflag" |
1793 | |
1794 | "launchpad.net/juju-core/cmd" |
1795 | + "launchpad.net/juju-core/cmd/envcmd" |
1796 | "launchpad.net/juju-core/environs/filestorage" |
1797 | "launchpad.net/juju-core/environs/simplestreams" |
1798 | "launchpad.net/juju-core/environs/storage" |
1799 | @@ -22,7 +23,7 @@ |
1800 | |
1801 | // ToolsMetadataCommand is used to generate simplestreams metadata for juju tools. |
1802 | type ToolsMetadataCommand struct { |
1803 | - cmd.EnvCommandBase |
1804 | + envcmd.EnvCommandBase |
1805 | fetch bool |
1806 | metadataDir string |
1807 | public bool |
1808 | @@ -41,6 +42,14 @@ |
1809 | f.BoolVar(&c.public, "public", false, "tools are for a public cloud, so generate mirrors information") |
1810 | } |
1811 | |
1812 | +func (c *ToolsMetadataCommand) Init(args []string) (err error) { |
1813 | + err = c.EnvCommandBase.Init() |
1814 | + if err != nil { |
1815 | + return |
1816 | + } |
1817 | + return cmd.CheckEmpty(args) |
1818 | +} |
1819 | + |
1820 | func (c *ToolsMetadataCommand) Run(context *cmd.Context) error { |
1821 | loggo.RegisterWriter("toolsmetadata", cmd.NewCommandLogWriter("juju.environs.tools", context.Stdout, context.Stderr), loggo.INFO) |
1822 | defer loggo.RemoveWriter("toolsmetadata") |
1823 | |
1824 | === modified file 'cmd/plugins/juju-metadata/validateimagemetadata.go' |
1825 | --- cmd/plugins/juju-metadata/validateimagemetadata.go 2014-03-21 03:27:16 +0000 |
1826 | +++ cmd/plugins/juju-metadata/validateimagemetadata.go 2014-04-01 14:32:48 +0000 |
1827 | @@ -12,6 +12,7 @@ |
1828 | "launchpad.net/gnuflag" |
1829 | |
1830 | "launchpad.net/juju-core/cmd" |
1831 | + "launchpad.net/juju-core/cmd/envcmd" |
1832 | "launchpad.net/juju-core/environs" |
1833 | "launchpad.net/juju-core/environs/config" |
1834 | "launchpad.net/juju-core/environs/configstore" |
1835 | @@ -22,7 +23,7 @@ |
1836 | |
1837 | // ValidateImageMetadataCommand |
1838 | type ValidateImageMetadataCommand struct { |
1839 | - cmd.EnvCommandBase |
1840 | + envcmd.EnvCommandBase |
1841 | out cmd.Output |
1842 | providerType string |
1843 | metadataDir string |
1844 | @@ -91,6 +92,10 @@ |
1845 | } |
1846 | |
1847 | func (c *ValidateImageMetadataCommand) Init(args []string) error { |
1848 | + err := c.EnvCommandBase.Init() |
1849 | + if err != nil { |
1850 | + return err |
1851 | + } |
1852 | if c.providerType != "" { |
1853 | if c.series == "" { |
1854 | return fmt.Errorf("series required if provider type is specified") |
1855 | @@ -102,7 +107,7 @@ |
1856 | return fmt.Errorf("metadata directory required if provider type is specified") |
1857 | } |
1858 | } |
1859 | - return c.EnvCommandBase.Init(args) |
1860 | + return nil |
1861 | } |
1862 | |
1863 | var _ environs.ConfigGetter = (*overrideEnvStream)(nil) |
1864 | |
1865 | === modified file 'cmd/plugins/juju-metadata/validatetoolsmetadata.go' |
1866 | --- cmd/plugins/juju-metadata/validatetoolsmetadata.go 2014-03-21 03:27:16 +0000 |
1867 | +++ cmd/plugins/juju-metadata/validatetoolsmetadata.go 2014-04-01 14:32:48 +0000 |
1868 | @@ -11,6 +11,7 @@ |
1869 | "launchpad.net/gnuflag" |
1870 | |
1871 | "launchpad.net/juju-core/cmd" |
1872 | + "launchpad.net/juju-core/cmd/envcmd" |
1873 | "launchpad.net/juju-core/environs" |
1874 | "launchpad.net/juju-core/environs/configstore" |
1875 | "launchpad.net/juju-core/environs/simplestreams" |
1876 | @@ -22,7 +23,7 @@ |
1877 | |
1878 | // ValidateToolsMetadataCommand |
1879 | type ValidateToolsMetadataCommand struct { |
1880 | - cmd.EnvCommandBase |
1881 | + envcmd.EnvCommandBase |
1882 | out cmd.Output |
1883 | providerType string |
1884 | metadataDir string |
1885 | @@ -117,6 +118,10 @@ |
1886 | } |
1887 | |
1888 | func (c *ValidateToolsMetadataCommand) Init(args []string) error { |
1889 | + err := c.EnvCommandBase.Init() |
1890 | + if err != nil { |
1891 | + return err |
1892 | + } |
1893 | if c.providerType != "" { |
1894 | if c.region == "" { |
1895 | return fmt.Errorf("region required if provider type is specified") |
1896 | @@ -134,7 +139,7 @@ |
1897 | return err |
1898 | } |
1899 | } |
1900 | - return c.EnvCommandBase.Init(args) |
1901 | + return nil |
1902 | } |
1903 | |
1904 | func (c *ValidateToolsMetadataCommand) Run(context *cmd.Context) error { |
1905 | |
1906 | === modified file 'cmd/plugins/juju-restore/restore.go' |
1907 | --- cmd/plugins/juju-restore/restore.go 2014-03-26 12:38:12 +0000 |
1908 | +++ cmd/plugins/juju-restore/restore.go 2014-04-01 14:32:48 +0000 |
1909 | @@ -19,6 +19,7 @@ |
1910 | "launchpad.net/goyaml" |
1911 | |
1912 | "launchpad.net/juju-core/cmd" |
1913 | + "launchpad.net/juju-core/cmd/envcmd" |
1914 | "launchpad.net/juju-core/constraints" |
1915 | "launchpad.net/juju-core/environs" |
1916 | "launchpad.net/juju-core/environs/bootstrap" |
1917 | @@ -64,7 +65,7 @@ |
1918 | ` |
1919 | |
1920 | type restoreCommand struct { |
1921 | - cmd.EnvCommandBase |
1922 | + envcmd.EnvCommandBase |
1923 | Log cmd.Log |
1924 | Constraints constraints.Value |
1925 | backupFile string |
1926 | @@ -88,6 +89,10 @@ |
1927 | } |
1928 | |
1929 | func (c *restoreCommand) Init(args []string) error { |
1930 | + err := c.EnvCommandBase.Init() |
1931 | + if err != nil { |
1932 | + return err |
1933 | + } |
1934 | if c.showDescription { |
1935 | return cmd.CheckEmpty(args) |
1936 | } |
1937 | |
1938 | === modified file 'cmd/supercommand.go' |
1939 | --- cmd/supercommand.go 2014-03-20 06:01:50 +0000 |
1940 | +++ cmd/supercommand.go 2014-04-01 14:32:48 +0000 |
1941 | @@ -13,7 +13,6 @@ |
1942 | |
1943 | "github.com/juju/loggo" |
1944 | "launchpad.net/gnuflag" |
1945 | - |
1946 | "launchpad.net/juju-core/version" |
1947 | ) |
1948 | |
1949 | |
1950 | === modified file 'environs/configstore/disk.go' |
1951 | --- environs/configstore/disk.go 2014-03-12 10:59:17 +0000 |
1952 | +++ environs/configstore/disk.go 2014-04-01 14:32:48 +0000 |
1953 | @@ -30,6 +30,14 @@ |
1954 | dir string |
1955 | } |
1956 | |
1957 | +type EnvironInfoData struct { |
1958 | + User string |
1959 | + Password string |
1960 | + StateServers []string `json:"state-servers" yaml:"state-servers"` |
1961 | + CACert string `json:"ca-cert" yaml:"ca-cert"` |
1962 | + Config map[string]interface{} `json:"bootstrap-config,omitempty" yaml:"bootstrap-config,omitempty"` |
1963 | +} |
1964 | + |
1965 | type environInfo struct { |
1966 | path string |
1967 | // initialized signifies whether the info has been written. |
1968 | @@ -37,12 +45,9 @@ |
1969 | |
1970 | // created signifies whether the info was returned from |
1971 | // a CreateInfo call. |
1972 | - created bool |
1973 | - User string |
1974 | - Password string |
1975 | - StateServers []string `yaml:"state-servers"` |
1976 | - CACert string `yaml:"ca-cert"` |
1977 | - Config map[string]interface{} `yaml:"bootstrap-config,omitempty"` |
1978 | + created bool |
1979 | + |
1980 | + EnvInfo EnvironInfoData |
1981 | } |
1982 | |
1983 | // NewDisk returns a ConfigStorage implementation that stores |
1984 | @@ -106,7 +111,7 @@ |
1985 | if len(data) == 0 { |
1986 | return &info, nil |
1987 | } |
1988 | - if err := goyaml.Unmarshal(data, &info); err != nil { |
1989 | + if err := goyaml.Unmarshal(data, &info.EnvInfo); err != nil { |
1990 | return nil, fmt.Errorf("error unmarshalling %q: %v", path, err) |
1991 | } |
1992 | info.initialized = true |
1993 | @@ -120,22 +125,22 @@ |
1994 | |
1995 | // BootstrapConfig implements EnvironInfo.BootstrapConfig. |
1996 | func (info *environInfo) BootstrapConfig() map[string]interface{} { |
1997 | - return info.Config |
1998 | + return info.EnvInfo.Config |
1999 | } |
2000 | |
2001 | // APICredentials implements EnvironInfo.APICredentials. |
2002 | func (info *environInfo) APICredentials() APICredentials { |
2003 | return APICredentials{ |
2004 | - User: info.User, |
2005 | - Password: info.Password, |
2006 | + User: info.EnvInfo.User, |
2007 | + Password: info.EnvInfo.Password, |
2008 | } |
2009 | } |
2010 | |
2011 | // APIEndpoint implements EnvironInfo.APIEndpoint. |
2012 | func (info *environInfo) APIEndpoint() APIEndpoint { |
2013 | return APIEndpoint{ |
2014 | - Addresses: info.StateServers, |
2015 | - CACert: info.CACert, |
2016 | + Addresses: info.EnvInfo.StateServers, |
2017 | + CACert: info.EnvInfo.CACert, |
2018 | } |
2019 | } |
2020 | |
2021 | @@ -144,19 +149,19 @@ |
2022 | if !info.created { |
2023 | panic("bootstrap config set on environment info that has not just been created") |
2024 | } |
2025 | - info.Config = attrs |
2026 | + info.EnvInfo.Config = attrs |
2027 | } |
2028 | |
2029 | // SetAPIEndpoint implements EnvironInfo.SetAPIEndpoint. |
2030 | func (info *environInfo) SetAPIEndpoint(endpoint APIEndpoint) { |
2031 | - info.StateServers = endpoint.Addresses |
2032 | - info.CACert = endpoint.CACert |
2033 | + info.EnvInfo.StateServers = endpoint.Addresses |
2034 | + info.EnvInfo.CACert = endpoint.CACert |
2035 | } |
2036 | |
2037 | // SetAPICredentials implements EnvironInfo.SetAPICredentials. |
2038 | func (info *environInfo) SetAPICredentials(creds APICredentials) { |
2039 | - info.User = creds.User |
2040 | - info.Password = creds.Password |
2041 | + info.EnvInfo.User = creds.User |
2042 | + info.EnvInfo.Password = creds.Password |
2043 | } |
2044 | |
2045 | // Location returns the location of the environInfo in human readable format. |
2046 | @@ -166,7 +171,7 @@ |
2047 | |
2048 | // Write implements EnvironInfo.Write. |
2049 | func (info *environInfo) Write() error { |
2050 | - data, err := goyaml.Marshal(info) |
2051 | + data, err := goyaml.Marshal(info.EnvInfo) |
2052 | if err != nil { |
2053 | return errgo.Annotate(err, "cannot marshal environment info") |
2054 | } |
2055 | |
2056 | === modified file 'environs/configstore/mem.go' |
2057 | --- environs/configstore/mem.go 2014-03-06 12:50:38 +0000 |
2058 | +++ environs/configstore/mem.go 2014-04-01 14:32:48 +0000 |
2059 | @@ -28,10 +28,10 @@ |
2060 | // references, which makes this OK to do. |
2061 | info1 := *info |
2062 | newAttrs := make(map[string]interface{}) |
2063 | - for name, attr := range info.Config { |
2064 | + for name, attr := range info.EnvInfo.Config { |
2065 | newAttrs[name] = attr |
2066 | } |
2067 | - info1.Config = newAttrs |
2068 | + info1.EnvInfo.Config = newAttrs |
2069 | info1.created = false |
2070 | return &info1 |
2071 | } |
2072 | |
2073 | === modified file 'environs/manual/init_test.go' |
2074 | --- environs/manual/init_test.go 2014-03-13 07:54:56 +0000 |
2075 | +++ environs/manual/init_test.go 2014-04-01 14:32:48 +0000 |
2076 | @@ -43,7 +43,7 @@ |
2077 | // will return an error. stderr will be included in the error message. |
2078 | defer installFakeSSH(c, manual.DetectionScript, []string{scriptResponse, "oh noes"}, 33)() |
2079 | hc, _, err := manual.DetectSeriesAndHardwareCharacteristics("hostname") |
2080 | - c.Assert(err, gc.ErrorMatches, "rc: 33 \\(oh noes\\)") |
2081 | + c.Assert(err, gc.ErrorMatches, "subprocess encountered error code 33 \\(oh noes\\)") |
2082 | // if the script doesn't fail, stderr is simply ignored. |
2083 | defer installFakeSSH(c, manual.DetectionScript, []string{scriptResponse, "non-empty-stderr"}, 0)() |
2084 | hc, _, err = manual.DetectSeriesAndHardwareCharacteristics("hostname") |
2085 | @@ -134,7 +134,7 @@ |
2086 | // will return an error. stderr will be included in the error message. |
2087 | defer installFakeSSH(c, manual.CheckProvisionedScript, []string{"non-empty-stdout", "non-empty-stderr"}, 255)() |
2088 | _, err = manual.CheckProvisioned("example.com") |
2089 | - c.Assert(err, gc.ErrorMatches, "rc: 255 \\(non-empty-stderr\\)") |
2090 | + c.Assert(err, gc.ErrorMatches, "subprocess encountered error code 255 \\(non-empty-stderr\\)") |
2091 | } |
2092 | |
2093 | func (s *initialisationSuite) TestInitUbuntuUserNonExisting(c *gc.C) { |
2094 | @@ -153,5 +153,5 @@ |
2095 | defer installFakeSSH(c, "", []string{"", "failed to create ubuntu user"}, 123)() |
2096 | defer installFakeSSH(c, "", "", 1)() // simulate failure of ubuntu@ login |
2097 | err := manual.InitUbuntuUser("testhost", "testuser", "", nil, nil) |
2098 | - c.Assert(err, gc.ErrorMatches, "rc: 123 \\(failed to create ubuntu user\\)") |
2099 | + c.Assert(err, gc.ErrorMatches, "subprocess encountered error code 123 \\(failed to create ubuntu user\\)") |
2100 | } |
2101 | |
2102 | === modified file 'environs/manual/provisioner_test.go' |
2103 | --- environs/manual/provisioner_test.go 2014-03-17 03:17:04 +0000 |
2104 | +++ environs/manual/provisioner_test.go 2014-04-01 14:32:48 +0000 |
2105 | @@ -75,7 +75,7 @@ |
2106 | }.install(c).Restore() |
2107 | machineId, err = manual.ProvisionMachine(args) |
2108 | if errorCode != 0 { |
2109 | - c.Assert(err, gc.ErrorMatches, fmt.Sprintf("rc: %d", errorCode)) |
2110 | + c.Assert(err, gc.ErrorMatches, fmt.Sprintf("subprocess encountered error code %d", errorCode)) |
2111 | c.Assert(machineId, gc.Equals, "") |
2112 | } else { |
2113 | c.Assert(err, gc.IsNil) |
2114 | @@ -109,7 +109,7 @@ |
2115 | SkipProvisionAgent: true, |
2116 | }.install(c).Restore() |
2117 | _, err = manual.ProvisionMachine(args) |
2118 | - c.Assert(err, gc.ErrorMatches, "error checking if provisioned: rc: 255") |
2119 | + c.Assert(err, gc.ErrorMatches, "error checking if provisioned: subprocess encountered error code 255") |
2120 | } |
2121 | |
2122 | func (s *provisionerSuite) TestFinishMachineConfig(c *gc.C) { |
2123 | |
2124 | === modified file 'juju/api.go' |
2125 | --- juju/api.go 2014-03-31 12:24:52 +0000 |
2126 | +++ juju/api.go 2014-04-01 14:32:48 +0000 |
2127 | @@ -19,6 +19,7 @@ |
2128 | "launchpad.net/juju-core/names" |
2129 | "launchpad.net/juju-core/state/api" |
2130 | "launchpad.net/juju-core/state/api/keymanager" |
2131 | + "launchpad.net/juju-core/state/api/usermanager" |
2132 | "launchpad.net/juju-core/utils/parallel" |
2133 | ) |
2134 | |
2135 | @@ -102,6 +103,14 @@ |
2136 | return keymanager.NewClient(st), nil |
2137 | } |
2138 | |
2139 | +func NewUserManagerClient(envName string) (*usermanager.Client, error) { |
2140 | + st, err := newAPIClient(envName) |
2141 | + if err != nil { |
2142 | + return nil, err |
2143 | + } |
2144 | + return usermanager.NewClient(st), nil |
2145 | +} |
2146 | + |
2147 | // NewAPIFromName returns an api.State connected to the API Server for |
2148 | // the named environment. If envName is "", the default environment will |
2149 | // be used. |
2150 | |
2151 | === modified file 'state/api/params/params.go' |
2152 | --- state/api/params/params.go 2014-03-31 12:30:31 +0000 |
2153 | +++ state/api/params/params.go 2014-04-01 14:32:48 +0000 |
2154 | @@ -361,6 +361,12 @@ |
2155 | Keys []string |
2156 | } |
2157 | |
2158 | +// ModifyUser stores the parameters used for a UserManager.Add|Remove call |
2159 | +type ModifyUser struct { |
2160 | + Tag string |
2161 | + Password string |
2162 | +} |
2163 | + |
2164 | // MarshalJSON implements json.Marshaler. |
2165 | func (d *Delta) MarshalJSON() ([]byte, error) { |
2166 | b, err := json.Marshal(d.Entity) |
2167 | |
2168 | === modified file 'state/apiserver/client/api_test.go' |
2169 | --- state/apiserver/client/api_test.go 2014-03-13 13:42:50 +0000 |
2170 | +++ state/apiserver/client/api_test.go 2014-04-01 14:32:48 +0000 |
2171 | @@ -267,7 +267,7 @@ |
2172 | setDefaultPassword(c, u) |
2173 | add(u) |
2174 | |
2175 | - u, err = s.State.AddUser("other", "") |
2176 | + u, err = s.State.AddUser("other", "password") |
2177 | c.Assert(err, gc.IsNil) |
2178 | setDefaultPassword(c, u) |
2179 | add(u) |
2180 | |
2181 | === modified file 'state/user_test.go' |
2182 | --- state/user_test.go 2014-03-13 13:42:50 +0000 |
2183 | +++ state/user_test.go 2014-04-01 14:32:48 +0000 |
2184 | @@ -58,7 +58,7 @@ |
2185 | } |
2186 | |
2187 | func (s *UserSuite) TestSetPassword(c *gc.C) { |
2188 | - u, err := s.State.AddUser("someuser", "") |
2189 | + u, err := s.State.AddUser("someuser", "password") |
2190 | c.Assert(err, gc.IsNil) |
2191 | |
2192 | testSetPassword(c, func() (state.Authenticator, error) { |
2193 | @@ -92,7 +92,7 @@ |
2194 | } |
2195 | |
2196 | func (s *UserSuite) TestSetPasswordHash(c *gc.C) { |
2197 | - u, err := s.State.AddUser("someuser", "") |
2198 | + u, err := s.State.AddUser("someuser", "password") |
2199 | c.Assert(err, gc.IsNil) |
2200 | |
2201 | err = u.SetPasswordHash(utils.UserPasswordHash("foo", utils.CompatSalt), utils.CompatSalt) |
2202 | @@ -111,7 +111,7 @@ |
2203 | } |
2204 | |
2205 | func (s *UserSuite) TestSetPasswordHashWithSalt(c *gc.C) { |
2206 | - u, err := s.State.AddUser("someuser", "") |
2207 | + u, err := s.State.AddUser("someuser", "password") |
2208 | c.Assert(err, gc.IsNil) |
2209 | |
2210 | err = u.SetPasswordHash(utils.UserPasswordHash("foo", "salted"), "salted") |
2211 | @@ -124,7 +124,7 @@ |
2212 | } |
2213 | |
2214 | func (s *UserSuite) TestPasswordValidUpdatesSalt(c *gc.C) { |
2215 | - u, err := s.State.AddUser("someuser", "") |
2216 | + u, err := s.State.AddUser("someuser", "password") |
2217 | c.Assert(err, gc.IsNil) |
2218 | |
2219 | compatHash := utils.UserPasswordHash("foo", utils.CompatSalt) |
2220 | @@ -152,7 +152,7 @@ |
2221 | } |
2222 | |
2223 | func (s *UserSuite) TestName(c *gc.C) { |
2224 | - u, err := s.State.AddUser("someuser", "") |
2225 | + u, err := s.State.AddUser("someuser", "password") |
2226 | c.Assert(err, gc.IsNil) |
2227 | |
2228 | c.Assert(u.Name(), gc.Equals, "someuser") |
2229 | @@ -160,7 +160,7 @@ |
2230 | } |
2231 | |
2232 | func (s *UserSuite) TestDeactivate(c *gc.C) { |
2233 | - u, err := s.State.AddUser("someuser", "") |
2234 | + u, err := s.State.AddUser("someuser", "password") |
2235 | c.Assert(err, gc.IsNil) |
2236 | c.Assert(u.IsDeactivated(), gc.Equals, false) |
2237 | |
2238 | |
2239 | === modified file 'testing/environ.go' |
2240 | --- testing/environ.go 2014-02-18 17:15:06 +0000 |
2241 | +++ testing/environ.go 2014-04-01 14:32:48 +0000 |
2242 | @@ -240,8 +240,10 @@ |
2243 | return fake |
2244 | } |
2245 | |
2246 | -func MakeSampleHome(c *gc.C) *FakeHome { |
2247 | - return MakeFakeHome(c, SingleEnvConfig, SampleCertName) |
2248 | +func MakeSampleHome(c *gc.C, files ...TestFile) *FakeHome { |
2249 | + fake := MakeFakeHome(c, SingleEnvConfig, SampleCertName) |
2250 | + fake.AddFiles(c, files) |
2251 | + return fake |
2252 | } |
2253 | |
2254 | func MakeMultipleEnvHome(c *gc.C) *FakeHome { |
Reviewers: mp+210962_ code.launchpad. net,
Message:
Please take a look.
Description:
Preliminary support for basic juju id commands:
juju add-user <username> <password>
if password is not supplied uses gopass to take the password from the
command line
juju remove-user <username>
doesn't actually remove the user. But mark them as inactive
add-user and remove-user aren't registered yet as they are useless
without
login. But the details of this are still being worked out.
This branch also contains fixes for lp:1285256.
The EnvCommandBase struct includes a function for ensuring the envname
is not "".
This replaces a review at https:/ /codereview. appspot. com/51450047/
https:/ /code.launchpad .net/~mattyw/ juju-core/ user-add- remove- cli/+merge/ 210962
(do not edit description out of merge proposal)
Please review this at https:/ /codereview. appspot. com/75600044/
Affected files (+497, -109 lines): environmentcomm and.go environmentcomm and_test. go export_ test.go addmachine. go addrelation. go adduser_ test.go authorisedkeys_ add.go authorisedkeys_ delete. go authorisedkeys_ import. go authorisedkeys_ list.go bootstrap. go cmd_test. go constraints. go debuglog_ test.go destroymachine. go destroyrelation .go destroyservice. go destroyunit. go endpoint. go environment. go publish_ test.go removeuser. go removeuser_ test.go resolved. go switch_ test.go synctools. go unexpose. go upgradecharm. go upgradejuju. go run_test. go juju-metadata/ imagemetadata. go juju-metadata/ toolsmetadata. go juju-metadata/ validateimageme tadata. go juju-metadata/ validatetoolsme tadata. go juju-restore/ restore. go vars_windows_ test.go params/ params. go /client/ api_test. go ssh_test. go
A [revision details]
M cmd/cmd.go
M cmd/envcmd/
M cmd/envcmd/
M cmd/envcmd/
M cmd/juju/
M cmd/juju/
M cmd/juju/addunit.go
A cmd/juju/adduser.go
A cmd/juju/
M cmd/juju/
M cmd/juju/
M cmd/juju/
M cmd/juju/
M cmd/juju/
M cmd/juju/
M cmd/juju/
M cmd/juju/
M cmd/juju/deploy.go
M cmd/juju/
M cmd/juju/
M cmd/juju/
M cmd/juju/
M cmd/juju/
M cmd/juju/
M cmd/juju/expose.go
M cmd/juju/get.go
M cmd/juju/plugin.go
M cmd/juju/publish.go
M cmd/juju/
A cmd/juju/
A cmd/juju/
M cmd/juju/
M cmd/juju/run.go
M cmd/juju/set.go
M cmd/juju/ssh.go
M cmd/juju/status.go
M cmd/juju/switch.go
M cmd/juju/
M cmd/juju/
M cmd/juju/
M cmd/juju/unset.go
M cmd/juju/
M cmd/juju/
M cmd/jujud/run.go
M cmd/jujud/
M cmd/package_test.go
M cmd/plugins/
M cmd/plugins/
M cmd/plugins/
M cmd/plugins/
M cmd/plugins/
M cmd/supercommand.go
M errors/errors.go
M juju/api.go
M juju/osenv/
M state/api/
M state/apiserver
M state/user.go
M state/user_test.go
M testing/environ.go
M utils/ssh/ssh.go
M utils/ssh/