github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/api/modelmanager/modelmanager.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package modelmanager
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"github.com/juju/loggo"
     9  	"github.com/juju/names"
    10  
    11  	"github.com/juju/juju/api/base"
    12  	"github.com/juju/juju/apiserver/params"
    13  	"github.com/juju/juju/juju/permission"
    14  )
    15  
    16  var logger = loggo.GetLogger("juju.api.modelmanager")
    17  
    18  // Client provides methods that the Juju client command uses to interact
    19  // with models stored in the Juju Server.
    20  type Client struct {
    21  	base.ClientFacade
    22  	facade base.FacadeCaller
    23  }
    24  
    25  // NewClient creates a new `Client` based on an existing authenticated API
    26  // connection.
    27  func NewClient(st base.APICallCloser) *Client {
    28  	frontend, backend := base.NewClientFacade(st, "ModelManager")
    29  	return &Client{ClientFacade: frontend, facade: backend}
    30  }
    31  
    32  // Close closes the api connection.
    33  func (c *Client) Close() error {
    34  	return c.ClientFacade.Close()
    35  }
    36  
    37  // ConfigSkeleton returns config values to be used as a starting point for the
    38  // API caller to construct a valid model specific config.  The provider
    39  // and region params are there for future use, and current behaviour expects
    40  // both of these to be empty.
    41  func (c *Client) ConfigSkeleton(provider, region string) (params.ModelConfig, error) {
    42  	var result params.ModelConfigResult
    43  	args := params.ModelSkeletonConfigArgs{
    44  		Provider: provider,
    45  		Region:   region,
    46  	}
    47  	err := c.facade.FacadeCall("ConfigSkeleton", args, &result)
    48  	if err != nil {
    49  		return nil, errors.Trace(err)
    50  	}
    51  	return result.Config, nil
    52  }
    53  
    54  // CreateModel creates a new model using the account and
    55  // model config specified in the args.
    56  func (c *Client) CreateModel(owner string, account, config map[string]interface{}) (params.Model, error) {
    57  	var result params.Model
    58  	if !names.IsValidUser(owner) {
    59  		return result, errors.Errorf("invalid owner name %q", owner)
    60  	}
    61  	createArgs := params.ModelCreateArgs{
    62  		OwnerTag: names.NewUserTag(owner).String(),
    63  		Account:  account,
    64  		Config:   config,
    65  	}
    66  	err := c.facade.FacadeCall("CreateModel", createArgs, &result)
    67  	if err != nil {
    68  		return result, errors.Trace(err)
    69  	}
    70  	return result, nil
    71  }
    72  
    73  // ListModels returns the models that the specified user
    74  // has access to in the current server.  Only that controller owner
    75  // can list models for any user (at this stage).  Other users
    76  // can only ask about their own models.
    77  func (c *Client) ListModels(user string) ([]base.UserModel, error) {
    78  	var models params.UserModelList
    79  	if !names.IsValidUser(user) {
    80  		return nil, errors.Errorf("invalid user name %q", user)
    81  	}
    82  	entity := params.Entity{names.NewUserTag(user).String()}
    83  	err := c.facade.FacadeCall("ListModels", entity, &models)
    84  	if err != nil {
    85  		return nil, errors.Trace(err)
    86  	}
    87  	result := make([]base.UserModel, len(models.UserModels))
    88  	for i, model := range models.UserModels {
    89  		owner, err := names.ParseUserTag(model.OwnerTag)
    90  		if err != nil {
    91  			return nil, errors.Annotatef(err, "OwnerTag %q at position %d", model.OwnerTag, i)
    92  		}
    93  		result[i] = base.UserModel{
    94  			Name:           model.Name,
    95  			UUID:           model.UUID,
    96  			Owner:          owner.Canonical(),
    97  			LastConnection: model.LastConnection,
    98  		}
    99  	}
   100  	return result, nil
   101  }
   102  
   103  func (c *Client) ModelInfo(tags []names.ModelTag) ([]params.ModelInfoResult, error) {
   104  	entities := params.Entities{
   105  		Entities: make([]params.Entity, len(tags)),
   106  	}
   107  	for i, tag := range tags {
   108  		entities.Entities[i].Tag = tag.String()
   109  	}
   110  	var results params.ModelInfoResults
   111  	err := c.facade.FacadeCall("ModelInfo", entities, &results)
   112  	if err != nil {
   113  		return nil, errors.Trace(err)
   114  	}
   115  	if len(results.Results) != len(tags) {
   116  		return nil, errors.Errorf("expected %d result(s), got %d", len(tags), len(results.Results))
   117  	}
   118  	return results.Results, nil
   119  }
   120  
   121  // ParseModelAccess parses an access permission argument into
   122  // a type suitable for making an API facade call.
   123  func ParseModelAccess(access string) (params.ModelAccessPermission, error) {
   124  	var fail params.ModelAccessPermission
   125  
   126  	modelAccess, err := permission.ParseModelAccess(access)
   127  	if err != nil {
   128  		return fail, errors.Trace(err)
   129  	}
   130  	var accessPermission params.ModelAccessPermission
   131  	switch modelAccess {
   132  	case permission.ModelReadAccess:
   133  		accessPermission = params.ModelReadAccess
   134  	case permission.ModelWriteAccess:
   135  		accessPermission = params.ModelWriteAccess
   136  	default:
   137  		return fail, errors.Errorf("unsupported model access permission %v", modelAccess)
   138  	}
   139  	return accessPermission, nil
   140  }
   141  
   142  // GrantModel grants a user access to the specified models.
   143  func (c *Client) GrantModel(user, access string, modelUUIDs ...string) error {
   144  	return c.modifyModelUser(params.GrantModelAccess, user, access, modelUUIDs)
   145  }
   146  
   147  // RevokeModel revokes a user's access to the specified models.
   148  func (c *Client) RevokeModel(user, access string, modelUUIDs ...string) error {
   149  	return c.modifyModelUser(params.RevokeModelAccess, user, access, modelUUIDs)
   150  }
   151  
   152  func (c *Client) modifyModelUser(action params.ModelAction, user, access string, modelUUIDs []string) error {
   153  	var args params.ModifyModelAccessRequest
   154  
   155  	if !names.IsValidUser(user) {
   156  		return errors.Errorf("invalid username: %q", user)
   157  	}
   158  	userTag := names.NewUserTag(user)
   159  
   160  	accessPermission, err := ParseModelAccess(access)
   161  	if err != nil {
   162  		return errors.Trace(err)
   163  	}
   164  	for _, model := range modelUUIDs {
   165  		if !names.IsValidModel(model) {
   166  			return errors.Errorf("invalid model: %q", model)
   167  		}
   168  		modelTag := names.NewModelTag(model)
   169  		args.Changes = append(args.Changes, params.ModifyModelAccess{
   170  			UserTag:  userTag.String(),
   171  			Action:   action,
   172  			Access:   accessPermission,
   173  			ModelTag: modelTag.String(),
   174  		})
   175  	}
   176  
   177  	var result params.ErrorResults
   178  	err = c.facade.FacadeCall("ModifyModelAccess", args, &result)
   179  	if err != nil {
   180  		return errors.Trace(err)
   181  	}
   182  	if len(result.Results) != len(args.Changes) {
   183  		return errors.Errorf("expected %d results, got %d", len(args.Changes), len(result.Results))
   184  	}
   185  
   186  	for i, r := range result.Results {
   187  		if r.Error != nil && r.Error.Code == params.CodeAlreadyExists {
   188  			logger.Warningf("model %q is already shared with %q", modelUUIDs[i], userTag.Canonical())
   189  			result.Results[i].Error = nil
   190  		}
   191  	}
   192  	return result.Combine()
   193  }