Skip to content

Commit

Permalink
controllers -> admins -> models
Browse files Browse the repository at this point in the history
  • Loading branch information
axw committed Feb 24, 2016
1 parent 486f4b7 commit a92c388
Show file tree
Hide file tree
Showing 9 changed files with 400 additions and 226 deletions.
File renamed without changes.
File renamed without changes.
217 changes: 149 additions & 68 deletions jujuclient/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,10 +192,13 @@ func (s *store) RemoveController(name string) error {
}

// UpdateModel implements ModelUpdater.
func (s *store) UpdateModel(controllerName, modelName string, details ModelDetails) error {
func (s *store) UpdateModel(controllerName, accountName, modelName string, details ModelDetails) error {
if err := ValidateControllerName(controllerName); err != nil {
return errors.Trace(err)
}
if err := ValidateAccountName(accountName); err != nil {
return errors.Trace(err)
}
if err := ValidateModelName(modelName); err != nil {
return errors.Trace(err)
}
Expand All @@ -209,33 +212,27 @@ func (s *store) UpdateModel(controllerName, modelName string, details ModelDetai
}
defer s.unlock(lock)

controllerModels, err := ReadModelsFile(JujuModelsPath())
if err != nil {
return errors.Trace(err)
}
if controllerModels == nil {
controllerModels = make(map[string]*ControllerModels)
}
models, ok := controllerModels[controllerName]
if !ok {
models = &ControllerModels{
Models: make(map[string]ModelDetails),
}
controllerModels[controllerName] = models
}
if oldDetails, ok := models.Models[modelName]; ok && details == oldDetails {
return nil
}

models.Models[modelName] = details
return errors.Trace(WriteModelsFile(controllerModels))
return errors.Trace(updateAccountModels(
controllerName, accountName,
func(models *AccountModels) (bool, error) {
oldDetails, ok := models.Models[modelName]
if ok && details == oldDetails {
return false, nil
}
models.Models[modelName] = details
return true, nil
},
))
}

// SetCurrentModel implements ModelUpdater.
func (s *store) SetCurrentModel(controllerName, modelName string) error {
func (s *store) SetCurrentModel(controllerName, accountName, modelName string) error {
if err := ValidateControllerName(controllerName); err != nil {
return errors.Trace(err)
}
if err := ValidateAccountName(accountName); err != nil {
return errors.Trace(err)
}
if err := ValidateModelName(modelName); err != nil {
return errors.Trace(err)
}
Expand All @@ -246,76 +243,106 @@ func (s *store) SetCurrentModel(controllerName, modelName string) error {
}
defer s.unlock(lock)

controllerModels, err := ReadModelsFile(JujuModelsPath())
if err != nil {
return errors.Trace(err)
}
models, ok := controllerModels[controllerName]
if !ok {
return errors.NotFoundf("controller %s", controllerName)
}
if models.CurrentModel == modelName {
return nil
}
if _, ok := models.Models[modelName]; !ok {
return errors.NotFoundf("model %s:%s", controllerName, modelName)
}

models.CurrentModel = modelName
return errors.Trace(WriteModelsFile(controllerModels))
return errors.Trace(updateAccountModels(
controllerName, accountName,
func(models *AccountModels) (bool, error) {
if models.CurrentModel == modelName {
return false, nil
}
if _, ok := models.Models[modelName]; !ok {
return false, errors.NotFoundf(
"model %s:%s:%s",
controllerName,
accountName,
modelName,
)
}
models.CurrentModel = modelName
return true, nil
},
))
}

// AllModels implements ModelGetter.
func (s *store) AllModels(controllerName string) (map[string]ModelDetails, error) {
func (s *store) AllModels(controllerName, accountName string) (map[string]ModelDetails, error) {
if err := ValidateControllerName(controllerName); err != nil {
return nil, errors.Trace(err)
}
if err := ValidateAccountName(accountName); err != nil {
return nil, errors.Trace(err)
}

lock, err := s.lock("read-all-models")
if err != nil {
return nil, errors.Trace(err)
}
defer s.unlock(lock)

controllerModels, err := ReadModelsFile(JujuModelsPath())
all, err := ReadModelsFile(JujuModelsPath())
if err != nil {
return nil, errors.Trace(err)
}
models, ok := controllerModels[controllerName]
controllerAccountModels, ok := all[controllerName]
if !ok {
return nil, errors.NotFoundf(
"models for controller %s",
controllerName,
)
}
accountModels, ok := controllerAccountModels.AccountModels[accountName]
if !ok {
return nil, errors.NotFoundf("models for controller %s", controllerName)
return nil, errors.NotFoundf(
"models for account %s on controller %s",
accountName, controllerName,
)
}
return models.Models, nil
return accountModels.Models, nil
}

// CurrentModel implements ModelGetter.
func (s *store) CurrentModel(controllerName string) (string, error) {
func (s *store) CurrentModel(controllerName, accountName string) (string, error) {
if err := ValidateControllerName(controllerName); err != nil {
return "", errors.Trace(err)
}
if err := ValidateAccountName(accountName); err != nil {
return "", errors.Trace(err)
}

lock, err := s.lock("read-current-model")
if err != nil {
return "", errors.Trace(err)
}
defer s.unlock(lock)

controllerModels, err := ReadModelsFile(JujuModelsPath())
all, err := ReadModelsFile(JujuModelsPath())
if err != nil {
return "", errors.Trace(err)
}
models, ok := controllerModels[controllerName]
if !ok || models.CurrentModel == "" {
return "", errors.NotFoundf("current model for controller %s", controllerName)
}
return models.CurrentModel, nil
controllerAccountModels, ok := all[controllerName]
if !ok {
return "", errors.NotFoundf(
"current model for controller %s",
controllerName,
)
}
accountModels, ok := controllerAccountModels.AccountModels[accountName]
if !ok || accountModels.CurrentModel == "" {
return "", errors.NotFoundf(
"current model for account %s on controller %s",
accountName, controllerName,
)
}
return accountModels.CurrentModel, nil
}

// ModelByName implements ModelGetter.
func (s *store) ModelByName(controllerName, modelName string) (*ModelDetails, error) {
func (s *store) ModelByName(controllerName, accountName, modelName string) (*ModelDetails, error) {
if err := ValidateControllerName(controllerName); err != nil {
return nil, errors.Trace(err)
}
if err := ValidateAccountName(accountName); err != nil {
return nil, errors.Trace(err)
}
if err := ValidateModelName(modelName); err != nil {
return nil, errors.Trace(err)
}
Expand All @@ -326,26 +353,44 @@ func (s *store) ModelByName(controllerName, modelName string) (*ModelDetails, er
}
defer s.unlock(lock)

controllerModels, err := ReadModelsFile(JujuModelsPath())
all, err := ReadModelsFile(JujuModelsPath())
if err != nil {
return nil, errors.Trace(err)
}
models, ok := controllerModels[controllerName]
controllerAccountModels, ok := all[controllerName]
if !ok {
return nil, errors.NotFoundf("controller %s", controllerName)
return nil, errors.NotFoundf(
"models for controller %s",
controllerName,
)
}
accountModels, ok := controllerAccountModels.AccountModels[accountName]
if !ok {
return nil, errors.NotFoundf(
"models for account %s on controller %s",
accountName, controllerName,
)
}
details, ok := models.Models[modelName]
details, ok := accountModels.Models[modelName]
if !ok {
return nil, errors.NotFoundf("model %s:%s", controllerName, modelName)
return nil, errors.NotFoundf(
"model %s:%s:%s",
controllerName,
accountName,
modelName,
)
}
return &details, nil
}

// RemoveModel implements ModelRemover.
func (s *store) RemoveModel(controllerName, modelName string) error {
func (s *store) RemoveModel(controllerName, accountName, modelName string) error {
if err := ValidateControllerName(controllerName); err != nil {
return errors.Trace(err)
}
if err := ValidateAccountName(accountName); err != nil {
return errors.Trace(err)
}
if err := ValidateModelName(modelName); err != nil {
return errors.Trace(err)
}
Expand All @@ -356,23 +401,59 @@ func (s *store) RemoveModel(controllerName, modelName string) error {
}
defer s.unlock(lock)

controllerModels, err := ReadModelsFile(JujuModelsPath())
return errors.Trace(updateAccountModels(
controllerName, accountName,
func(models *AccountModels) (bool, error) {
if _, ok := models.Models[modelName]; !ok {
return false, errors.NotFoundf(
"model %s:%s:%s",
controllerName,
accountName,
modelName,
)
}
delete(models.Models, modelName)
if models.CurrentModel == modelName {
models.CurrentModel = modelName
}
return true, nil
},
))
}

func updateAccountModels(
controllerName, accountName string,
update func(*AccountModels) (bool, error),
) error {
all, err := ReadModelsFile(JujuModelsPath())
if err != nil {
return errors.Trace(err)
}
models, ok := controllerModels[controllerName]
if all == nil {
all = make(map[string]ControllerAccountModels)
}
controllerAccountModels, ok := all[controllerName]
if !ok {
return errors.NotFoundf("controller %s", controllerName)
controllerAccountModels = ControllerAccountModels{
make(map[string]*AccountModels),
}
all[controllerName] = controllerAccountModels
}
accountModels, ok := controllerAccountModels.AccountModels[accountName]
if !ok {
accountModels = &AccountModels{
Models: make(map[string]ModelDetails),
}
controllerAccountModels.AccountModels[accountName] = accountModels
}
if _, ok := models.Models[modelName]; !ok {
return errors.NotFoundf("model %s:%s", controllerName, modelName)
updated, err := update(accountModels)
if err != nil {
return errors.Trace(err)
}

delete(models.Models, modelName)
if models.CurrentModel == modelName {
models.CurrentModel = ""
if updated {
return errors.Trace(WriteModelsFile(all))
}
return errors.Trace(WriteModelsFile(controllerModels))
return nil
}

// UpdateAccount implements AccountUpdater.
Expand Down
50 changes: 26 additions & 24 deletions jujuclient/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,43 +68,45 @@ type ModelUpdater interface {
//
// If the model does not already exist, it will be added.
// Otherwise, it will be overwritten with the new details.
UpdateModel(controllerName, modelName string, details ModelDetails) error
UpdateModel(controllerName, accountName, modelName string, details ModelDetails) error

// SetCurrentModel sets the name of the current model for
// the specified controller. If there exists no model with
// the specified names, an error satisfing errors.IsNotFound
// will be returned.
SetCurrentModel(controllerName, modelName string) error
// the specified controller and account. If there exists no
// model with the specified names, an error satisfing
// errors.IsNotFound will be returned.
SetCurrentModel(controllerName, accountName, modelName string) error
}

// ModelRemover removes models.
type ModelRemover interface {
// RemoveModel removes the model with the given controller and model
// names from the models collection. If there is no model with the
// specified names, an errors satisfying errors.IsNotFound will be
// returned.
RemoveModel(controllerName, modelName string) error
// RemoveModel removes the model with the given controller, account,
// and model names from the models collection. If there is no model
// with the specified names, an errors satisfying errors.IsNotFound
// will be returned.
RemoveModel(controllerName, accountName, modelName string) error
}

// ModelGetter gets models.
type ModelGetter interface {
// AllModels gets all models for the specified controller.
// AllModels gets all models for the specified controller and
// account.
//
// If there is no controller with the specified name, or
// no models cached for the controller, an error satisfying
// errors.IsNotFound will be returned.
AllModels(controllerName string) (map[string]ModelDetails, error)
// If there is no controller or account with the specified
// names, or no models cached for the controller and account,
// an error satisfying errors.IsNotFound will be returned.
AllModels(controllerName, accountName string) (map[string]ModelDetails, error)

// CurrentModel returns the name of the current model for
// the specified controller. If there is no current model
// for the controller, an error satisfying errors.IsNotFound
// is returned.
CurrentModel(controllerName string) (string, error)

// ModelByName returns the model with the specified controller
// and model names. If there exists no model with the specified
// names, an error satisfying errors.IsNotFound will be returned.
ModelByName(controllerName, modelName string) (*ModelDetails, error)
// the specified controller and account. If there is no current
// model for the controller and account, an error satisfying
// errors.IsNotFound is returned.
CurrentModel(controllerName, accountName string) (string, error)

// ModelByName returns the model with the specified controller,
// account, and model names. If there exists no model with the
// specified names, an error satisfying errors.IsNotFound will
// be returned.
ModelByName(controllerName, accountName, modelName string) (*ModelDetails, error)
}

// AccountUpdater stores account details.
Expand Down
Loading

0 comments on commit a92c388

Please sign in to comment.