github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/api/usermanager/client.go (about)

     1  // Copyright 2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package usermanager
     5  
     6  import (
     7  	"fmt"
     8  	"strings"
     9  
    10  	"github.com/juju/errors"
    11  	"github.com/juju/loggo"
    12  	"github.com/juju/names"
    13  
    14  	"github.com/juju/juju/api/base"
    15  	"github.com/juju/juju/apiserver/params"
    16  )
    17  
    18  var logger = loggo.GetLogger("juju.api.usermanager")
    19  
    20  // Client provides methods that the Juju client command uses to interact
    21  // with users stored in the Juju Server.
    22  type Client struct {
    23  	base.ClientFacade
    24  	facade base.FacadeCaller
    25  }
    26  
    27  // NewClient creates a new `Client` based on an existing authenticated API
    28  // connection.
    29  func NewClient(st base.APICallCloser) *Client {
    30  	frontend, backend := base.NewClientFacade(st, "UserManager")
    31  	return &Client{ClientFacade: frontend, facade: backend}
    32  }
    33  
    34  // AddUser creates a new local user in the juju server.
    35  func (c *Client) AddUser(username, displayName, password string) (names.UserTag, error) {
    36  	if !names.IsValidUser(username) {
    37  		return names.UserTag{}, fmt.Errorf("invalid user name %q", username)
    38  	}
    39  	userArgs := params.AddUsers{
    40  		Users: []params.AddUser{{Username: username, DisplayName: displayName, Password: password}},
    41  	}
    42  	var results params.AddUserResults
    43  	err := c.facade.FacadeCall("AddUser", userArgs, &results)
    44  	if err != nil {
    45  		return names.UserTag{}, errors.Trace(err)
    46  	}
    47  	if count := len(results.Results); count != 1 {
    48  		logger.Errorf("expected 1 result, got %#v", results)
    49  		return names.UserTag{}, errors.Errorf("expected 1 result, got %d", count)
    50  	}
    51  	result := results.Results[0]
    52  	if result.Error != nil {
    53  		return names.UserTag{}, errors.Trace(result.Error)
    54  	}
    55  	tag, err := names.ParseUserTag(result.Tag)
    56  	if err != nil {
    57  		return names.UserTag{}, errors.Trace(err)
    58  	}
    59  	logger.Infof("created user %s", result.Tag)
    60  	return tag, nil
    61  }
    62  
    63  func (c *Client) userCall(username string, methodCall string) error {
    64  	if !names.IsValidUserName(username) {
    65  		return errors.Errorf("%q is not a valid username", username)
    66  	}
    67  	tag := names.NewLocalUserTag(username)
    68  
    69  	var results params.ErrorResults
    70  	args := params.Entities{
    71  		[]params.Entity{{tag.String()}},
    72  	}
    73  	err := c.facade.FacadeCall(methodCall, args, &results)
    74  	if err != nil {
    75  		return errors.Trace(err)
    76  	}
    77  	return results.OneError()
    78  }
    79  
    80  // DisableUser disables a user.  If the user is already disabled, the action
    81  // is consided a success.
    82  func (c *Client) DisableUser(username string) error {
    83  	return c.userCall(username, "DisableUser")
    84  }
    85  
    86  // EnableUser enables a users.  If the user is already enabled, the action is
    87  // consided a success.
    88  func (c *Client) EnableUser(username string) error {
    89  	return c.userCall(username, "EnableUser")
    90  }
    91  
    92  // IncludeDisabled is a type alias to avoid bare true/false values
    93  // in calls to the client method.
    94  type IncludeDisabled bool
    95  
    96  var (
    97  	// ActiveUsers indicates to only return active users.
    98  	ActiveUsers IncludeDisabled = false
    99  	// AllUsers indicates that both enabled and disabled users should be
   100  	// returned.
   101  	AllUsers IncludeDisabled = true
   102  )
   103  
   104  // UserInfo returns information about the specified users.  If no users are
   105  // specified, the call should return all users.  If includeDisabled is set to
   106  // ActiveUsers, only enabled users are returned.
   107  func (c *Client) UserInfo(usernames []string, all IncludeDisabled) ([]params.UserInfo, error) {
   108  	var results params.UserInfoResults
   109  	var entities []params.Entity
   110  	for _, username := range usernames {
   111  		if !names.IsValidUserName(username) {
   112  			return nil, errors.Errorf("%q is not a valid username", username)
   113  		}
   114  		tag := names.NewLocalUserTag(username)
   115  		entities = append(entities, params.Entity{Tag: tag.String()})
   116  	}
   117  	args := params.UserInfoRequest{
   118  		Entities:        entities,
   119  		IncludeDisabled: bool(all),
   120  	}
   121  	err := c.facade.FacadeCall("UserInfo", args, &results)
   122  	if err != nil {
   123  		return nil, errors.Trace(err)
   124  	}
   125  	// Only need to look for errors if users were explicitly specified, because
   126  	// if we didn't ask for any, we should get all, and we shouldn't get any
   127  	// errors for listing all.  We care here because we index into the users
   128  	// slice.
   129  	if len(results.Results) == len(usernames) {
   130  		var errorStrings []string
   131  		for i, result := range results.Results {
   132  			if result.Error != nil {
   133  				annotated := errors.Annotate(result.Error, usernames[i])
   134  				errorStrings = append(errorStrings, annotated.Error())
   135  			}
   136  		}
   137  		if len(errorStrings) > 0 {
   138  			return nil, errors.New(strings.Join(errorStrings, ", "))
   139  		}
   140  	}
   141  	info := []params.UserInfo{}
   142  	for i, result := range results.Results {
   143  		if result.Result == nil {
   144  			return nil, errors.Errorf("unexpected nil result at position %d", i)
   145  		}
   146  		info = append(info, *result.Result)
   147  	}
   148  	return info, nil
   149  }
   150  
   151  // SetPassword changes the password for the specified user.
   152  func (c *Client) SetPassword(username, password string) error {
   153  	if !names.IsValidUserName(username) {
   154  		return errors.Errorf("%q is not a valid username", username)
   155  	}
   156  	tag := names.NewLocalUserTag(username)
   157  	args := params.EntityPasswords{
   158  		Changes: []params.EntityPassword{{
   159  			Tag:      tag.String(),
   160  			Password: password}},
   161  	}
   162  	var results params.ErrorResults
   163  	err := c.facade.FacadeCall("SetPassword", args, &results)
   164  	if err != nil {
   165  		return err
   166  	}
   167  	return results.OneError()
   168  }