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 }