Skip to content

Commit

Permalink
cmd/...: qualify model names with owner
Browse files Browse the repository at this point in the history
jujuclient now expects model names to be
qualified with the owner name. In modelcmd
we wrap the provided ClientStore such that
any user-specified model name is qualified
before it reaches the underlying jujuclient.

list-models is updated as follows:
 - if --all is used, model names are always
   displayed with the owner-qualification,
   e.g. admin/controller.
 - otherwise, the owner will be omitted if
   it is the same as the user for whom
   models are being listed
 - if the owner is to be shown, the domain
   is only included for non-local users
  • Loading branch information
axw committed Jul 19, 2016
1 parent 4f9c938 commit 35e1627
Show file tree
Hide file tree
Showing 33 changed files with 530 additions and 270 deletions.
2 changes: 1 addition & 1 deletion cmd/juju/application/cmd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func initExpectations(com *DeployCommand, store jujuclient.ClientStore) {
if com.NumUnits == 0 {
com.NumUnits = 1
}
com.SetClientStore(store)
com.SetClientStore(modelcmd.QualifyingClientStore{store})
com.SetModelName("controller")
}

Expand Down
14 changes: 7 additions & 7 deletions cmd/juju/commands/bootstrap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ func (s *BootstrapSuite) run(c *gc.C, test bootstrapTest) testing.Restorer {
c.Assert(controller.APIEndpoints, gc.DeepEquals, addrConnectedTo)
c.Assert(utils.IsValidUUIDString(controller.ControllerUUID), jc.IsTrue)

controllerModel, err := s.store.ModelByName(controllerName, bootstrap.ControllerModelName)
controllerModel, err := s.store.ModelByName(controllerName, "admin@local/controller")
c.Assert(err, jc.ErrorIsNil)
c.Assert(controllerModel.ModelUUID, gc.Equals, controller.ControllerUUID)

Expand Down Expand Up @@ -395,7 +395,7 @@ func (s *BootstrapSuite) TestBootstrapSetsCurrentModel(c *gc.C) {
c.Assert(currentController, gc.Equals, "devcontroller")
modelName, err := s.store.CurrentModel(currentController)
c.Assert(err, jc.ErrorIsNil)
c.Assert(modelName, gc.Equals, "default")
c.Assert(modelName, gc.Equals, "admin@local/default")
}

func (s *BootstrapSuite) TestBootstrapDefaultModel(c *gc.C) {
Expand Down Expand Up @@ -591,11 +591,11 @@ func (s *BootstrapSuite) TestBootstrapErrorRestoresOldMetadata(c *gc.C) {
jujuclient.ClientStore,
bootstrap.PrepareParams,
) (environs.Environ, error) {
s.writeControllerModelAccountInfo(c, "foo", "bar", "foobar@local")
s.writeControllerModelAccountInfo(c, "foo", "foobar@local/bar", "foobar@local")
return nil, fmt.Errorf("mock-prepare")
})

s.writeControllerModelAccountInfo(c, "olddevcontroller", "fredmodel", "fred@local")
s.writeControllerModelAccountInfo(c, "olddevcontroller", "fred@local/fredmodel", "fred@local")
_, err := coretesting.RunCommand(c, s.newBootstrapCommand(), "devcontroller", "dummy", "--auto-upgrade")
c.Assert(err, gc.ErrorMatches, "mock-prepare")

Expand All @@ -606,14 +606,14 @@ func (s *BootstrapSuite) TestBootstrapErrorRestoresOldMetadata(c *gc.C) {
c.Assert(accountDetails.User, gc.Equals, "fred@local")
currentModel, err := s.store.CurrentModel(currentController)
c.Assert(err, jc.ErrorIsNil)
c.Assert(currentModel, gc.Equals, "fredmodel")
c.Assert(currentModel, gc.Equals, "fred@local/fredmodel")
}

func (s *BootstrapSuite) TestBootstrapAlreadyExists(c *gc.C) {
const controllerName = "devcontroller"
s.patchVersionAndSeries(c, "raring")

s.writeControllerModelAccountInfo(c, "devcontroller", "fredmodel", "fred@local")
s.writeControllerModelAccountInfo(c, "devcontroller", "fred@local/fredmodel", "fred@local")

ctx := coretesting.Context(c)
_, errc := cmdtesting.RunCommand(ctx, s.newBootstrapCommand(), controllerName, "dummy", "--auto-upgrade")
Expand All @@ -627,7 +627,7 @@ func (s *BootstrapSuite) TestBootstrapAlreadyExists(c *gc.C) {
c.Assert(accountDetails.User, gc.Equals, "fred@local")
currentModel, err := s.store.CurrentModel(currentController)
c.Assert(err, jc.ErrorIsNil)
c.Assert(currentModel, gc.Equals, "fredmodel")
c.Assert(currentModel, gc.Equals, "fred@local/fredmodel")
}

func (s *BootstrapSuite) TestInvalidLocalSource(c *gc.C) {
Expand Down
2 changes: 1 addition & 1 deletion cmd/juju/commands/migrate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func (s *MigrateSuite) SetUpTest(c *gc.C) {
c.Assert(err, jc.ErrorIsNil)

// Define the model to migrate in the config.
err = s.store.UpdateModel("source", "model", jujuclient.ModelDetails{
err = s.store.UpdateModel("source", "source@local/model", jujuclient.ModelDetails{
ModelUUID: modelUUID,
})
c.Assert(err, jc.ErrorIsNil)
Expand Down
34 changes: 19 additions & 15 deletions cmd/juju/commands/switch.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,17 +71,18 @@ func (c *switchCommand) Init(args []string) error {
}

func (c *switchCommand) Run(ctx *cmd.Context) (resultErr error) {
store := modelcmd.QualifyingClientStore{c.Store}

// Get the current name for logging the transition or printing
// the current controller/model.
currentControllerName, err := c.Store.CurrentController()
currentControllerName, err := store.CurrentController()
if errors.IsNotFound(err) {
currentControllerName = ""
} else if err != nil {
return errors.Trace(err)
}
if c.Target == "" {
currentName, err := c.name(currentControllerName, true)
currentName, err := c.name(store, currentControllerName, true)
if err != nil {
return errors.Trace(err)
}
Expand All @@ -91,7 +92,7 @@ func (c *switchCommand) Run(ctx *cmd.Context) (resultErr error) {
fmt.Fprintf(ctx.Stdout, "%s\n", currentName)
return nil
}
currentName, err := c.name(currentControllerName, false)
currentName, err := c.name(store, currentControllerName, false)
if err != nil {
return errors.Trace(err)
}
Expand All @@ -114,16 +115,16 @@ func (c *switchCommand) Run(ctx *cmd.Context) (resultErr error) {

// If the target identifies a controller, then set that as the current controller.
var newControllerName = c.Target
if _, err = c.Store.ControllerByName(c.Target); err == nil {
if _, err = store.ControllerByName(c.Target); err == nil {
if newControllerName == currentControllerName {
newName = currentName
return nil
} else {
newName, err = c.name(newControllerName, false)
newName, err = c.name(store, newControllerName, false)
if err != nil {
return errors.Trace(err)
}
return errors.Trace(c.Store.SetCurrentController(newControllerName))
return errors.Trace(store.SetCurrentController(newControllerName))
}
} else if !errors.IsNotFound(err) {
return errors.Trace(err)
Expand All @@ -135,25 +136,28 @@ func (c *switchCommand) Run(ctx *cmd.Context) (resultErr error) {
// case, the model must exist in the current controller.
newControllerName, modelName := modelcmd.SplitModelName(c.Target)
if newControllerName != "" {
if _, err = c.Store.ControllerByName(newControllerName); err != nil {
if _, err = store.ControllerByName(newControllerName); err != nil {
return errors.Trace(err)
}
newName = modelcmd.JoinModelName(newControllerName, modelName)
} else {
if currentControllerName == "" {
return unknownSwitchTargetError(c.Target)
}
newControllerName = currentControllerName
newName = modelcmd.JoinModelName(newControllerName, modelName)
}
modelName, err = store.QualifiedModelName(newControllerName, modelName)
if err != nil {
return errors.Trace(err)
}
newName = modelcmd.JoinModelName(newControllerName, modelName)

err = c.Store.SetCurrentModel(newControllerName, modelName)
err = store.SetCurrentModel(newControllerName, modelName)
if errors.IsNotFound(err) {
// The model isn't known locally, so we must query the controller.
if err := c.RefreshModels(c.Store, newControllerName); err != nil {
if err := c.RefreshModels(store, newControllerName); err != nil {
return errors.Annotate(err, "refreshing models cache")
}
err := c.Store.SetCurrentModel(newControllerName, modelName)
err := store.SetCurrentModel(newControllerName, modelName)
if errors.IsNotFound(err) {
return unknownSwitchTargetError(c.Target)
} else if err != nil {
Expand All @@ -163,7 +167,7 @@ func (c *switchCommand) Run(ctx *cmd.Context) (resultErr error) {
return errors.Trace(err)
}
if currentControllerName != newControllerName {
if err := c.Store.SetCurrentController(newControllerName); err != nil {
if err := store.SetCurrentController(newControllerName); err != nil {
return errors.Trace(err)
}
}
Expand All @@ -185,11 +189,11 @@ func logSwitch(ctx *cmd.Context, oldName string, newName *string) {
// name returns the name of the current model for the specified controller
// if one is set, otherwise the controller name with an indicator that it
// is the name of a controller and not a model.
func (c *switchCommand) name(controllerName string, machineReadable bool) (string, error) {
func (c *switchCommand) name(store jujuclient.ModelGetter, controllerName string, machineReadable bool) (string, error) {
if controllerName == "" {
return "", nil
}
modelName, err := c.Store.CurrentModel(controllerName)
modelName, err := store.CurrentModel(controllerName)
if err == nil {
return modelcmd.JoinModelName(controllerName, modelName), nil
}
Expand Down
74 changes: 44 additions & 30 deletions cmd/juju/commands/switch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,12 @@ func (s *SwitchSimpleSuite) TestNoArgsCurrentModel(c *gc.C) {
s.addController(c, "a-controller")
s.store.CurrentControllerName = "a-controller"
s.store.Models["a-controller"] = &jujuclient.ControllerModels{
Models: map[string]jujuclient.ModelDetails{"mymodel": {}},
CurrentModel: "mymodel",
Models: map[string]jujuclient.ModelDetails{"admin@local/mymodel": {}},
CurrentModel: "admin@local/mymodel",
}
ctx, err := s.run(c)
c.Assert(err, jc.ErrorIsNil)
c.Assert(coretesting.Stdout(ctx), gc.Equals, "a-controller:mymodel\n")
c.Assert(coretesting.Stdout(ctx), gc.Equals, "a-controller:admin@local/mymodel\n")
}

func (s *SwitchSimpleSuite) TestSwitchWritesCurrentController(c *gc.C) {
Expand Down Expand Up @@ -131,80 +131,100 @@ func (s *SwitchSimpleSuite) TestSwitchControllerToModel(c *gc.C) {
s.store.CurrentControllerName = "ctrl"
s.addController(c, "ctrl")
s.store.Models["ctrl"] = &jujuclient.ControllerModels{
Models: map[string]jujuclient.ModelDetails{"mymodel": {}},
Models: map[string]jujuclient.ModelDetails{"admin@local/mymodel": {}},
}
context, err := s.run(c, "mymodel")
c.Assert(err, jc.ErrorIsNil)
c.Assert(coretesting.Stderr(context), gc.Equals, "ctrl (controller) -> ctrl:mymodel\n")
c.Assert(coretesting.Stderr(context), gc.Equals, "ctrl (controller) -> ctrl:admin@local/mymodel\n")
s.stubStore.CheckCalls(c, []testing.StubCall{
{"CurrentController", nil},
{"CurrentModel", []interface{}{"ctrl"}},
{"ControllerByName", []interface{}{"mymodel"}},
{"SetCurrentModel", []interface{}{"ctrl", "mymodel"}},
{"AccountDetails", []interface{}{"ctrl"}},
{"SetCurrentModel", []interface{}{"ctrl", "admin@local/mymodel"}},
})
c.Assert(s.store.Models["ctrl"].CurrentModel, gc.Equals, "mymodel")
c.Assert(s.store.Models["ctrl"].CurrentModel, gc.Equals, "admin@local/mymodel")
}

func (s *SwitchSimpleSuite) TestSwitchControllerToModelDifferentController(c *gc.C) {
s.store.CurrentControllerName = "old"
s.addController(c, "new")
s.store.Models["new"] = &jujuclient.ControllerModels{
Models: map[string]jujuclient.ModelDetails{"mymodel": {}},
Models: map[string]jujuclient.ModelDetails{"admin@local/mymodel": {}},
}
context, err := s.run(c, "new:mymodel")
c.Assert(err, jc.ErrorIsNil)
c.Assert(coretesting.Stderr(context), gc.Equals, "old (controller) -> new:mymodel\n")
c.Assert(coretesting.Stderr(context), gc.Equals, "old (controller) -> new:admin@local/mymodel\n")
s.stubStore.CheckCalls(c, []testing.StubCall{
{"CurrentController", nil},
{"CurrentModel", []interface{}{"old"}},
{"ControllerByName", []interface{}{"new:mymodel"}},
{"ControllerByName", []interface{}{"new"}},
{"SetCurrentModel", []interface{}{"new", "mymodel"}},
{"AccountDetails", []interface{}{"new"}},
{"SetCurrentModel", []interface{}{"new", "admin@local/mymodel"}},
{"SetCurrentController", []interface{}{"new"}},
})
c.Assert(s.store.Models["new"].CurrentModel, gc.Equals, "mymodel")
c.Assert(s.store.Models["new"].CurrentModel, gc.Equals, "admin@local/mymodel")
}

func (s *SwitchSimpleSuite) TestSwitchLocalControllerToModelDifferentController(c *gc.C) {
s.store.CurrentControllerName = "old"
s.addController(c, "new")
s.store.Models["new"] = &jujuclient.ControllerModels{
Models: map[string]jujuclient.ModelDetails{"mymodel": {}},
Models: map[string]jujuclient.ModelDetails{"admin@local/mymodel": {}},
}
context, err := s.run(c, "new:mymodel")
c.Assert(err, jc.ErrorIsNil)
c.Assert(coretesting.Stderr(context), gc.Equals, "old (controller) -> new:mymodel\n")
c.Assert(coretesting.Stderr(context), gc.Equals, "old (controller) -> new:admin@local/mymodel\n")
s.stubStore.CheckCalls(c, []testing.StubCall{
{"CurrentController", nil},
{"CurrentModel", []interface{}{"old"}},
{"ControllerByName", []interface{}{"new:mymodel"}},
{"ControllerByName", []interface{}{"new"}},
{"SetCurrentModel", []interface{}{"new", "mymodel"}},
{"AccountDetails", []interface{}{"new"}},
{"SetCurrentModel", []interface{}{"new", "admin@local/mymodel"}},
{"SetCurrentController", []interface{}{"new"}},
})
c.Assert(s.store.Models["new"].CurrentModel, gc.Equals, "mymodel")
c.Assert(s.store.Models["new"].CurrentModel, gc.Equals, "admin@local/mymodel")
}

func (s *SwitchSimpleSuite) TestSwitchControllerToDifferentControllerCurrentModel(c *gc.C) {
s.store.CurrentControllerName = "old"
s.addController(c, "new")
s.store.Models["new"] = &jujuclient.ControllerModels{
Models: map[string]jujuclient.ModelDetails{"mymodel": {}},
CurrentModel: "mymodel",
Models: map[string]jujuclient.ModelDetails{"admin@local/mymodel": {}},
CurrentModel: "admin@local/mymodel",
}
context, err := s.run(c, "new:mymodel")
c.Assert(err, jc.ErrorIsNil)
c.Assert(coretesting.Stderr(context), gc.Equals, "old (controller) -> new:mymodel\n")
c.Assert(coretesting.Stderr(context), gc.Equals, "old (controller) -> new:admin@local/mymodel\n")
s.stubStore.CheckCalls(c, []testing.StubCall{
{"CurrentController", nil},
{"CurrentModel", []interface{}{"old"}},
{"ControllerByName", []interface{}{"new:mymodel"}},
{"ControllerByName", []interface{}{"new"}},
{"SetCurrentModel", []interface{}{"new", "mymodel"}},
{"AccountDetails", []interface{}{"new"}},
{"SetCurrentModel", []interface{}{"new", "admin@local/mymodel"}},
{"SetCurrentController", []interface{}{"new"}},
})
}

func (s *SwitchSimpleSuite) TestSwitchToModelDifferentOwner(c *gc.C) {
s.store.CurrentControllerName = "same"
s.addController(c, "same")
s.store.Models["same"] = &jujuclient.ControllerModels{
Models: map[string]jujuclient.ModelDetails{
"admin@local/mymodel": {},
"bianca@local/mymodel": {},
},
CurrentModel: "admin@local/mymodel",
}
context, err := s.run(c, "bianca/mymodel")
c.Assert(err, jc.ErrorIsNil)
c.Assert(coretesting.Stderr(context), gc.Equals, "same:admin@local/mymodel -> same:bianca@local/mymodel\n")
c.Assert(s.store.Models["same"].CurrentModel, gc.Equals, "bianca@local/mymodel")
}

func (s *SwitchSimpleSuite) TestSwitchUnknownNoCurrentController(c *gc.C) {
_, err := s.run(c, "unknown")
c.Assert(err, gc.ErrorMatches, `"unknown" is not the name of a model or controller`)
Expand All @@ -219,25 +239,21 @@ func (s *SwitchSimpleSuite) TestSwitchUnknownCurrentControllerRefreshModels(c *g
s.addController(c, "ctrl")
s.onRefresh = func() {
s.store.Models["ctrl"] = &jujuclient.ControllerModels{
Models: map[string]jujuclient.ModelDetails{"unknown": {}},
Models: map[string]jujuclient.ModelDetails{"admin@local/unknown": {}},
}
}
ctx, err := s.run(c, "unknown")
c.Assert(err, jc.ErrorIsNil)
c.Assert(coretesting.Stderr(ctx), gc.Equals, "ctrl (controller) -> ctrl:unknown\n")
s.CheckCalls(c, []testing.StubCall{
{"RefreshModels", []interface{}{s.stubStore, "ctrl"}},
})
c.Assert(coretesting.Stderr(ctx), gc.Equals, "ctrl (controller) -> ctrl:admin@local/unknown\n")
s.CheckCallNames(c, "RefreshModels")
}

func (s *SwitchSimpleSuite) TestSwitchUnknownCurrentControllerRefreshModelsStillUnknown(c *gc.C) {
s.store.CurrentControllerName = "ctrl"
s.addController(c, "ctrl")
_, err := s.run(c, "unknown")
c.Assert(err, gc.ErrorMatches, `"unknown" is not the name of a model or controller`)
s.CheckCalls(c, []testing.StubCall{
{"RefreshModels", []interface{}{s.stubStore, "ctrl"}},
})
s.CheckCallNames(c, "RefreshModels")
}

func (s *SwitchSimpleSuite) TestSwitchUnknownCurrentControllerRefreshModelsFails(c *gc.C) {
Expand All @@ -246,9 +262,7 @@ func (s *SwitchSimpleSuite) TestSwitchUnknownCurrentControllerRefreshModelsFails
s.SetErrors(errors.New("not very refreshing"))
_, err := s.run(c, "unknown")
c.Assert(err, gc.ErrorMatches, "refreshing models cache: not very refreshing")
s.CheckCalls(c, []testing.StubCall{
{"RefreshModels", []interface{}{s.stubStore, "ctrl"}},
})
s.CheckCallNames(c, "RefreshModels")
}

func (s *SwitchSimpleSuite) TestSettingWhenEnvVarSet(c *gc.C) {
Expand Down
Loading

0 comments on commit 35e1627

Please sign in to comment.