github.com/rogpeppe/juju@v0.0.0-20140613142852-6337964b789e/state/api/params/params.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package params
     5  
     6  import (
     7  	"bytes"
     8  	"encoding/json"
     9  	"fmt"
    10  	"time"
    11  
    12  	"github.com/juju/charm"
    13  	"github.com/juju/utils/proxy"
    14  
    15  	"github.com/juju/juju/constraints"
    16  	"github.com/juju/juju/instance"
    17  	"github.com/juju/juju/network"
    18  	"github.com/juju/juju/utils/ssh"
    19  	"github.com/juju/juju/version"
    20  )
    21  
    22  // Entity identifies a single entity.
    23  type Entity struct {
    24  	Tag string
    25  }
    26  
    27  // Entities identifies multiple entities.
    28  type Entities struct {
    29  	Entities []Entity
    30  }
    31  
    32  // EntityPasswords holds the parameters for making a SetPasswords call.
    33  type EntityPasswords struct {
    34  	Changes []EntityPassword
    35  }
    36  
    37  // EntityPassword specifies a password change for the entity
    38  // with the given tag.
    39  type EntityPassword struct {
    40  	Tag      string
    41  	Password string
    42  }
    43  
    44  // ErrorResults holds the results of calling a bulk operation which
    45  // returns no data, only an error result. The order and
    46  // number of elements matches the operations specified in the request.
    47  type ErrorResults struct {
    48  	// Results contains the error results from each operation.
    49  	Results []ErrorResult
    50  }
    51  
    52  // OneError returns the error from the result
    53  // of a bulk operation on a single value.
    54  func (result ErrorResults) OneError() error {
    55  	if n := len(result.Results); n != 1 {
    56  		return fmt.Errorf("expected 1 result, got %d", n)
    57  	}
    58  	if err := result.Results[0].Error; err != nil {
    59  		return err
    60  	}
    61  	return nil
    62  }
    63  
    64  // ErrorResult holds the error status of a single operation.
    65  type ErrorResult struct {
    66  	Error *Error
    67  }
    68  
    69  // StatusData contains additional information for a status.
    70  type StatusData map[string]interface{}
    71  
    72  // AddRelation holds the parameters for making the AddRelation call.
    73  // The endpoints specified are unordered.
    74  type AddRelation struct {
    75  	Endpoints []string
    76  }
    77  
    78  // AddRelationResults holds the results of a AddRelation call. The Endpoints
    79  // field maps service names to the involved endpoints.
    80  type AddRelationResults struct {
    81  	Endpoints map[string]charm.Relation
    82  }
    83  
    84  // DestroyRelation holds the parameters for making the DestroyRelation call.
    85  // The endpoints specified are unordered.
    86  type DestroyRelation struct {
    87  	Endpoints []string
    88  }
    89  
    90  // AddMachineParams encapsulates the parameters used to create a new machine.
    91  type AddMachineParams struct {
    92  	// The following fields hold attributes that will be given to the
    93  	// new machine when it is created.
    94  	Series      string
    95  	Constraints constraints.Value
    96  	Jobs        []MachineJob
    97  
    98  	// If Placement is non-nil, it contains a placement directive
    99  	// that will be used to decide how to instantiate the machine.
   100  	Placement *instance.Placement
   101  
   102  	// If ParentId is non-empty, it specifies the id of the
   103  	// parent machine within which the new machine will
   104  	// be created. In that case, ContainerType must also be
   105  	// set.
   106  	ParentId string
   107  
   108  	// ContainerType optionally gives the container type of the
   109  	// new machine. If it is non-empty, the new machine
   110  	// will be implemented by a container. If it is specified
   111  	// but ParentId is empty, a new top level machine will
   112  	// be created to hold the container with given series,
   113  	// constraints and jobs.
   114  	ContainerType instance.ContainerType
   115  
   116  	// If InstanceId is non-empty, it will be associated with
   117  	// the new machine along with the given nonce,
   118  	// hardware characteristics and addresses.
   119  	// All the following fields will be ignored if ContainerType
   120  	// is set.
   121  	InstanceId              instance.Id
   122  	Nonce                   string
   123  	HardwareCharacteristics instance.HardwareCharacteristics
   124  	Addrs                   []network.Address
   125  }
   126  
   127  // AddMachines holds the parameters for making the
   128  // AddMachinesWithPlacement call.
   129  type AddMachines struct {
   130  	MachineParams []AddMachineParams
   131  }
   132  
   133  // AddMachinesResults holds the results of an AddMachines call.
   134  type AddMachinesResults struct {
   135  	Machines []AddMachinesResult
   136  }
   137  
   138  // AddMachinesResults holds the name of a machine added by the
   139  // state.api.client.AddMachine call for a single machine.
   140  type AddMachinesResult struct {
   141  	Machine string
   142  	Error   *Error
   143  }
   144  
   145  // DestroyMachines holds parameters for the DestroyMachines call.
   146  type DestroyMachines struct {
   147  	MachineNames []string
   148  	Force        bool
   149  }
   150  
   151  // ServiceDeploy holds the parameters for making the ServiceDeploy call.
   152  type ServiceDeploy struct {
   153  	ServiceName   string
   154  	CharmUrl      string
   155  	NumUnits      int
   156  	Config        map[string]string
   157  	ConfigYAML    string // Takes precedence over config if both are present.
   158  	Constraints   constraints.Value
   159  	ToMachineSpec string
   160  	Networks      []string
   161  }
   162  
   163  // ServiceUpdate holds the parameters for making the ServiceUpdate call.
   164  type ServiceUpdate struct {
   165  	ServiceName     string
   166  	CharmUrl        string
   167  	ForceCharmUrl   bool
   168  	MinUnits        *int
   169  	SettingsStrings map[string]string
   170  	SettingsYAML    string // Takes precedence over SettingsStrings if both are present.
   171  	Constraints     *constraints.Value
   172  }
   173  
   174  // ServiceSetCharm sets the charm for a given service.
   175  type ServiceSetCharm struct {
   176  	ServiceName string
   177  	CharmUrl    string
   178  	Force       bool
   179  }
   180  
   181  // ServiceExpose holds the parameters for making the ServiceExpose call.
   182  type ServiceExpose struct {
   183  	ServiceName string
   184  }
   185  
   186  // ServiceSet holds the parameters for a ServiceSet
   187  // command. Options contains the configuration data.
   188  type ServiceSet struct {
   189  	ServiceName string
   190  	Options     map[string]string
   191  }
   192  
   193  // ServiceSetYAML holds the parameters for
   194  // a ServiceSetYAML command. Config contains the
   195  // configuration data in YAML format.
   196  type ServiceSetYAML struct {
   197  	ServiceName string
   198  	Config      string
   199  }
   200  
   201  // ServiceUnset holds the parameters for a ServiceUnset
   202  // command. Options contains the option attribute names
   203  // to unset.
   204  type ServiceUnset struct {
   205  	ServiceName string
   206  	Options     []string
   207  }
   208  
   209  // ServiceGet holds parameters for making the ServiceGet or
   210  // ServiceGetCharmURL calls.
   211  type ServiceGet struct {
   212  	ServiceName string
   213  }
   214  
   215  // ServiceGetResults holds results of the ServiceGet call.
   216  type ServiceGetResults struct {
   217  	Service     string
   218  	Charm       string
   219  	Config      map[string]interface{}
   220  	Constraints constraints.Value
   221  }
   222  
   223  // ServiceCharmRelations holds parameters for making the ServiceCharmRelations call.
   224  type ServiceCharmRelations struct {
   225  	ServiceName string
   226  }
   227  
   228  // ServiceCharmRelationsResults holds the results of the ServiceCharmRelations call.
   229  type ServiceCharmRelationsResults struct {
   230  	CharmRelations []string
   231  }
   232  
   233  // ServiceUnexpose holds parameters for the ServiceUnexpose call.
   234  type ServiceUnexpose struct {
   235  	ServiceName string
   236  }
   237  
   238  // PublicAddress holds parameters for the PublicAddress call.
   239  type PublicAddress struct {
   240  	Target string
   241  }
   242  
   243  // PublicAddressResults holds results of the PublicAddress call.
   244  type PublicAddressResults struct {
   245  	PublicAddress string
   246  }
   247  
   248  // PrivateAddress holds parameters for the PrivateAddress call.
   249  type PrivateAddress struct {
   250  	Target string
   251  }
   252  
   253  // PrivateAddressResults holds results of the PrivateAddress call.
   254  type PrivateAddressResults struct {
   255  	PrivateAddress string
   256  }
   257  
   258  // Resolved holds parameters for the Resolved call.
   259  type Resolved struct {
   260  	UnitName string
   261  	Retry    bool
   262  }
   263  
   264  // ResolvedResults holds results of the Resolved call.
   265  type ResolvedResults struct {
   266  	Service  string
   267  	Charm    string
   268  	Settings map[string]interface{}
   269  }
   270  
   271  // AddServiceUnitsResults holds the names of the units added by the
   272  // AddServiceUnits call.
   273  type AddServiceUnitsResults struct {
   274  	Units []string
   275  }
   276  
   277  // AddServiceUnits holds parameters for the AddUnits call.
   278  type AddServiceUnits struct {
   279  	ServiceName   string
   280  	NumUnits      int
   281  	ToMachineSpec string
   282  }
   283  
   284  // DestroyServiceUnits holds parameters for the DestroyUnits call.
   285  type DestroyServiceUnits struct {
   286  	UnitNames []string
   287  }
   288  
   289  // ServiceDestroy holds the parameters for making the ServiceDestroy call.
   290  type ServiceDestroy struct {
   291  	ServiceName string
   292  }
   293  
   294  // Creds holds credentials for identifying an entity.
   295  type Creds struct {
   296  	AuthTag  string
   297  	Password string
   298  	Nonce    string
   299  }
   300  
   301  // GetAnnotationsResults holds annotations associated with an entity.
   302  type GetAnnotationsResults struct {
   303  	Annotations map[string]string
   304  }
   305  
   306  // GetAnnotations stores parameters for making the GetAnnotations call.
   307  type GetAnnotations struct {
   308  	Tag string
   309  }
   310  
   311  // SetAnnotations stores parameters for making the SetAnnotations call.
   312  type SetAnnotations struct {
   313  	Tag   string
   314  	Pairs map[string]string
   315  }
   316  
   317  // GetServiceConstraints stores parameters for making the GetServiceConstraints call.
   318  type GetServiceConstraints struct {
   319  	ServiceName string
   320  }
   321  
   322  // GetConstraintsResults holds results of the GetConstraints call.
   323  type GetConstraintsResults struct {
   324  	Constraints constraints.Value
   325  }
   326  
   327  // SetConstraints stores parameters for making the SetConstraints call.
   328  type SetConstraints struct {
   329  	ServiceName string //optional, if empty, environment constraints are set.
   330  	Constraints constraints.Value
   331  }
   332  
   333  // CharmInfo stores parameters for a CharmInfo call.
   334  type CharmInfo struct {
   335  	CharmURL string
   336  }
   337  
   338  // ResolveCharms stores charm references for a ResolveCharms call.
   339  type ResolveCharms struct {
   340  	References []charm.Reference
   341  }
   342  
   343  // ResolveCharmResult holds the result of resolving a charm reference to a URL, or any error that occurred.
   344  type ResolveCharmResult struct {
   345  	URL   *charm.URL `json:",omitempty"`
   346  	Error string     `json:",omitempty"`
   347  }
   348  
   349  // ResolveCharmResults holds results of the ResolveCharms call.
   350  type ResolveCharmResults struct {
   351  	URLs []ResolveCharmResult
   352  }
   353  
   354  // AllWatcherId holds the id of an AllWatcher.
   355  type AllWatcherId struct {
   356  	AllWatcherId string
   357  }
   358  
   359  // AllWatcherNextResults holds deltas returned from calling AllWatcher.Next().
   360  type AllWatcherNextResults struct {
   361  	Deltas []Delta
   362  }
   363  
   364  // Delta holds details of a change to the environment.
   365  type Delta struct {
   366  	// If Removed is true, the entity has been removed;
   367  	// otherwise it has been created or changed.
   368  	Removed bool
   369  	// Entity holds data about the entity that has changed.
   370  	Entity EntityInfo
   371  }
   372  
   373  // ListSSHKeys stores parameters used for a KeyManager.ListKeys call.
   374  type ListSSHKeys struct {
   375  	Entities
   376  	Mode ssh.ListMode
   377  }
   378  
   379  // ModifySSHKeys stores parameters used for a KeyManager.Add|Delete|Import call for a user.
   380  type ModifyUserSSHKeys struct {
   381  	User string
   382  	Keys []string
   383  }
   384  
   385  // ModifyUsers holds the parameters for making a UserManager Add or Modify calls.
   386  type ModifyUsers struct {
   387  	Changes []ModifyUser
   388  }
   389  
   390  // ModifyUser stores the parameters used for a UserManager.Add|Remove call.
   391  type ModifyUser struct {
   392  	// Tag is here purely for backwards compatability. Older clients will
   393  	// attempt to use the EntityPassword structure, so we need a Tag here
   394  	// (which will be treated as Username)
   395  	Tag         string
   396  	Username    string
   397  	DisplayName string
   398  	Password    string
   399  }
   400  
   401  // MarshalJSON implements json.Marshaler.
   402  func (d *Delta) MarshalJSON() ([]byte, error) {
   403  	b, err := json.Marshal(d.Entity)
   404  	if err != nil {
   405  		return nil, err
   406  	}
   407  	var buf bytes.Buffer
   408  	buf.WriteByte('[')
   409  	c := "change"
   410  	if d.Removed {
   411  		c = "remove"
   412  	}
   413  	fmt.Fprintf(&buf, "%q,%q,", d.Entity.EntityId().Kind, c)
   414  	buf.Write(b)
   415  	buf.WriteByte(']')
   416  	return buf.Bytes(), nil
   417  }
   418  
   419  // UnmarshalJSON implements json.Unmarshaler.
   420  func (d *Delta) UnmarshalJSON(data []byte) error {
   421  	var elements []json.RawMessage
   422  	if err := json.Unmarshal(data, &elements); err != nil {
   423  		return err
   424  	}
   425  	if len(elements) != 3 {
   426  		return fmt.Errorf(
   427  			"Expected 3 elements in top-level of JSON but got %d",
   428  			len(elements))
   429  	}
   430  	var entityKind, operation string
   431  	if err := json.Unmarshal(elements[0], &entityKind); err != nil {
   432  		return err
   433  	}
   434  	if err := json.Unmarshal(elements[1], &operation); err != nil {
   435  		return err
   436  	}
   437  	if operation == "remove" {
   438  		d.Removed = true
   439  	} else if operation != "change" {
   440  		return fmt.Errorf("Unexpected operation %q", operation)
   441  	}
   442  	switch entityKind {
   443  	case "machine":
   444  		d.Entity = new(MachineInfo)
   445  	case "service":
   446  		d.Entity = new(ServiceInfo)
   447  	case "unit":
   448  		d.Entity = new(UnitInfo)
   449  	case "relation":
   450  		d.Entity = new(RelationInfo)
   451  	case "annotation":
   452  		d.Entity = new(AnnotationInfo)
   453  	default:
   454  		return fmt.Errorf("Unexpected entity name %q", entityKind)
   455  	}
   456  	if err := json.Unmarshal(elements[2], &d.Entity); err != nil {
   457  		return err
   458  	}
   459  	return nil
   460  }
   461  
   462  // EntityInfo is implemented by all entity Info types.
   463  type EntityInfo interface {
   464  	// EntityId returns an identifier that will uniquely
   465  	// identify the entity within its kind
   466  	EntityId() EntityId
   467  }
   468  
   469  // IMPORTANT NOTE: the types below are direct subsets of the entity docs
   470  // held in mongo, as defined in the state package (serviceDoc,
   471  // machineDoc etc).
   472  // In particular, the document marshalled into mongo
   473  // must unmarshal correctly into these documents.
   474  // If the format of a field in a document is changed in mongo, or
   475  // a field is removed and it coincides with one of the
   476  // fields below, a similar change must be made here.
   477  //
   478  // MachineInfo corresponds with state.machineDoc.
   479  // ServiceInfo corresponds with state.serviceDoc.
   480  // UnitInfo corresponds with state.unitDoc.
   481  // RelationInfo corresponds with state.relationDoc.
   482  // AnnotationInfo corresponds with state.annotatorDoc.
   483  
   484  var (
   485  	_ EntityInfo = (*MachineInfo)(nil)
   486  	_ EntityInfo = (*ServiceInfo)(nil)
   487  	_ EntityInfo = (*UnitInfo)(nil)
   488  	_ EntityInfo = (*RelationInfo)(nil)
   489  	_ EntityInfo = (*AnnotationInfo)(nil)
   490  )
   491  
   492  type EntityId struct {
   493  	Kind string
   494  	Id   interface{}
   495  }
   496  
   497  // StateServingInfo holds information needed by a state
   498  // server.
   499  type StateServingInfo struct {
   500  	APIPort    int
   501  	StatePort  int
   502  	Cert       string
   503  	PrivateKey string
   504  	// this will be passed as the KeyFile argument to MongoDB
   505  	SharedSecret   string
   506  	SystemIdentity string
   507  }
   508  
   509  // IsMasterResult holds the result of an IsMaster API call.
   510  type IsMasterResult struct {
   511  	// Master reports whether the connected agent
   512  	// lives on the same instance as the mongo replica
   513  	// set master.
   514  	Master bool
   515  }
   516  
   517  // MachineInfo holds the information about a Machine
   518  // that is watched by StateWatcher.
   519  type MachineInfo struct {
   520  	Id                       string `bson:"_id"`
   521  	InstanceId               string
   522  	Status                   Status
   523  	StatusInfo               string
   524  	StatusData               StatusData
   525  	Life                     Life
   526  	Series                   string
   527  	SupportedContainers      []instance.ContainerType
   528  	SupportedContainersKnown bool
   529  	HardwareCharacteristics  *instance.HardwareCharacteristics `json:",omitempty"`
   530  	Jobs                     []MachineJob
   531  	Addresses                []network.Address
   532  }
   533  
   534  func (i *MachineInfo) EntityId() EntityId {
   535  	return EntityId{
   536  		Kind: "machine",
   537  		Id:   i.Id,
   538  	}
   539  }
   540  
   541  type ServiceInfo struct {
   542  	Name        string `bson:"_id"`
   543  	Exposed     bool
   544  	CharmURL    string
   545  	OwnerTag    string
   546  	Life        Life
   547  	MinUnits    int
   548  	Constraints constraints.Value
   549  	Config      map[string]interface{}
   550  }
   551  
   552  func (i *ServiceInfo) EntityId() EntityId {
   553  	return EntityId{
   554  		Kind: "service",
   555  		Id:   i.Name,
   556  	}
   557  }
   558  
   559  type UnitInfo struct {
   560  	Name           string `bson:"_id"`
   561  	Service        string
   562  	Series         string
   563  	CharmURL       string
   564  	PublicAddress  string
   565  	PrivateAddress string
   566  	MachineId      string
   567  	Ports          []network.Port
   568  	Status         Status
   569  	StatusInfo     string
   570  	StatusData     StatusData
   571  }
   572  
   573  func (i *UnitInfo) EntityId() EntityId {
   574  	return EntityId{
   575  		Kind: "unit",
   576  		Id:   i.Name,
   577  	}
   578  }
   579  
   580  type Endpoint struct {
   581  	ServiceName string
   582  	Relation    charm.Relation
   583  }
   584  
   585  type RelationInfo struct {
   586  	Key       string `bson:"_id"`
   587  	Id        int
   588  	Endpoints []Endpoint
   589  }
   590  
   591  func (i *RelationInfo) EntityId() EntityId {
   592  	return EntityId{
   593  		Kind: "relation",
   594  		Id:   i.Key,
   595  	}
   596  }
   597  
   598  type AnnotationInfo struct {
   599  	Tag         string
   600  	Annotations map[string]string
   601  }
   602  
   603  func (i *AnnotationInfo) EntityId() EntityId {
   604  	return EntityId{
   605  		Kind: "annotation",
   606  		Id:   i.Tag,
   607  	}
   608  }
   609  
   610  // ContainerManagerConfigParams contains the parameters for the
   611  // ContainerManagerConfig provisioner API call.
   612  type ContainerManagerConfigParams struct {
   613  	Type instance.ContainerType
   614  }
   615  
   616  // ContainerManagerConfig contains information from the environment config
   617  // that is needed for configuring the container manager.
   618  type ContainerManagerConfig struct {
   619  	ManagerConfig map[string]string
   620  }
   621  
   622  // ContainerConfig contains information from the environment config that is
   623  // needed for container cloud-init.
   624  type ContainerConfig struct {
   625  	ProviderType            string
   626  	AuthorizedKeys          string
   627  	SSLHostnameVerification bool
   628  	Proxy                   proxy.Settings
   629  	AptProxy                proxy.Settings
   630  }
   631  
   632  // ProvisioningScriptParams contains the parameters for the
   633  // ProvisioningScript client API call.
   634  type ProvisioningScriptParams struct {
   635  	MachineId string
   636  	Nonce     string
   637  
   638  	// DataDir may be "", in which case the default will be used.
   639  	DataDir string
   640  
   641  	// DisablePackageCommands may be set to disable all package-related
   642  	// commands. It is then the responsibility of the provisioner to
   643  	// ensure that all the packages required by Juju are available.
   644  	DisablePackageCommands bool
   645  }
   646  
   647  // ProvisioningScriptResult contains the result of the
   648  // ProvisioningScript client API call.
   649  type ProvisioningScriptResult struct {
   650  	Script string
   651  }
   652  
   653  // EnvironmentGetResults contains the result of EnvironmentGet client
   654  // API call.
   655  type EnvironmentGetResults struct {
   656  	Config map[string]interface{}
   657  }
   658  
   659  // EnvironmentSet contains the arguments for EnvironmentSet client API
   660  // call.
   661  type EnvironmentSet struct {
   662  	Config map[string]interface{}
   663  }
   664  
   665  // EnvironmentUnset contains the arguments for EnvironmentUnset client API
   666  // call.
   667  type EnvironmentUnset struct {
   668  	Keys []string
   669  }
   670  
   671  // SetEnvironAgentVersion contains the arguments for
   672  // SetEnvironAgentVersion client API call.
   673  type SetEnvironAgentVersion struct {
   674  	Version version.Number
   675  }
   676  
   677  // DeployerConnectionValues containers the result of deployer.ConnectionInfo
   678  // API call.
   679  type DeployerConnectionValues struct {
   680  	StateAddresses []string
   681  	APIAddresses   []string
   682  }
   683  
   684  // StatusParams holds parameters for the Status call.
   685  type StatusParams struct {
   686  	Patterns []string
   687  }
   688  
   689  // SetRsyslogCertParams holds parameters for the SetRsyslogCert call.
   690  type SetRsyslogCertParams struct {
   691  	CACert []byte
   692  }
   693  
   694  // RsyslogConfigResult holds the result of a GetRsyslogConfig call.
   695  type RsyslogConfigResult struct {
   696  	Error  *Error
   697  	CACert string
   698  	// Port is only used by state servers as the port to listen on.
   699  	// Clients should use HostPorts for the rsyslog addresses to forward
   700  	// logs to.
   701  	Port      int
   702  	HostPorts []network.HostPort
   703  }
   704  
   705  // RsyslogConfigResults is the bulk form of RyslogConfigResult
   706  type RsyslogConfigResults struct {
   707  	Results []RsyslogConfigResult
   708  }
   709  
   710  // DistributionGroupResult contains the result of
   711  // the DistributionGroup provisioner API call.
   712  type DistributionGroupResult struct {
   713  	Error  *Error
   714  	Result []instance.Id
   715  }
   716  
   717  // DistributionGroupResults is the bulk form of
   718  // DistributionGroupResult.
   719  type DistributionGroupResults struct {
   720  	Results []DistributionGroupResult
   721  }
   722  
   723  // APIHostPortsResult holds the result of an APIHostPorts
   724  // call. Each element in the top level slice holds
   725  // the addresses for one API server.
   726  type APIHostPortsResult struct {
   727  	Servers [][]network.HostPort
   728  }
   729  
   730  // LoginResult holds the result of a Login call.
   731  type LoginResult struct {
   732  	Servers        [][]network.HostPort
   733  	EnvironTag     string
   734  	LastConnection *time.Time
   735  }
   736  
   737  // EnsureAvailability contains arguments for
   738  // the EnsureAvailability client API call.
   739  type EnsureAvailability struct {
   740  	NumStateServers int
   741  	Constraints     constraints.Value
   742  	// Series is the series to associate with new state server machines.
   743  	// If this is empty, then the environment's default series is used.
   744  	Series string
   745  }
   746  
   747  type UserInfo struct {
   748  	Username       string    `json:username`
   749  	DisplayName    string    `json:display-name`
   750  	CreatedBy      string    `json:created-by`
   751  	DateCreated    time.Time `json:date-created`
   752  	LastConnection time.Time `json:last-connection`
   753  }
   754  
   755  // UserInfoResult holds the result of a UserInfo call.
   756  type UserInfoResult struct {
   757  	Result *UserInfo `json:result,omitempty`
   758  	Error  *Error    `json:error,omitempty`
   759  }
   760  
   761  type UserInfoResults struct {
   762  	Results []UserInfoResult
   763  }