github.com/Pankov404/juju@v0.0.0-20150703034450-be266991dceb/api/client.go (about)

     1  // Copyright 2013, 2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package api
     5  
     6  import (
     7  	"bytes"
     8  	"crypto/tls"
     9  	"encoding/json"
    10  	"fmt"
    11  	"io"
    12  	"io/ioutil"
    13  	"net/http"
    14  	"net/url"
    15  	"os"
    16  	"path"
    17  	"strings"
    18  	"time"
    19  
    20  	"github.com/juju/errors"
    21  	"github.com/juju/loggo"
    22  	"github.com/juju/names"
    23  	"github.com/juju/utils"
    24  	"golang.org/x/net/websocket"
    25  	"gopkg.in/juju/charm.v5"
    26  	"gopkg.in/macaroon.v1"
    27  
    28  	"github.com/juju/juju/api/base"
    29  	"github.com/juju/juju/apiserver/params"
    30  	"github.com/juju/juju/constraints"
    31  	"github.com/juju/juju/instance"
    32  	"github.com/juju/juju/network"
    33  	"github.com/juju/juju/state/multiwatcher"
    34  	"github.com/juju/juju/tools"
    35  	"github.com/juju/juju/version"
    36  )
    37  
    38  // Client represents the client-accessible part of the state.
    39  type Client struct {
    40  	base.ClientFacade
    41  	facade base.FacadeCaller
    42  	st     *State
    43  }
    44  
    45  // NetworksSpecification holds the enabled and disabled networks for a
    46  // service.
    47  type NetworksSpecification struct {
    48  	Enabled  []string
    49  	Disabled []string
    50  }
    51  
    52  // AgentStatus holds status info about a machine or unit agent.
    53  type AgentStatus struct {
    54  	Status  params.Status
    55  	Info    string
    56  	Data    map[string]interface{}
    57  	Since   *time.Time
    58  	Kind    params.HistoryKind
    59  	Version string
    60  	Life    string
    61  	Err     error
    62  }
    63  
    64  // MachineStatus holds status info about a machine.
    65  type MachineStatus struct {
    66  	Agent AgentStatus
    67  
    68  	// The following fields mirror fields in AgentStatus (introduced
    69  	// in 1.19.x). The old fields below are being kept for
    70  	// compatibility with old clients.
    71  	// They can be removed once API versioning lands.
    72  	AgentState     params.Status
    73  	AgentStateInfo string
    74  	AgentVersion   string
    75  	Life           string
    76  	Err            error
    77  
    78  	DNSName       string
    79  	InstanceId    instance.Id
    80  	InstanceState string
    81  	Series        string
    82  	Id            string
    83  	Containers    map[string]MachineStatus
    84  	Hardware      string
    85  	Jobs          []multiwatcher.MachineJob
    86  	HasVote       bool
    87  	WantsVote     bool
    88  }
    89  
    90  // ServiceStatus holds status info about a service.
    91  type ServiceStatus struct {
    92  	Err           error
    93  	Charm         string
    94  	Exposed       bool
    95  	Life          string
    96  	Relations     map[string][]string
    97  	Networks      NetworksSpecification
    98  	CanUpgradeTo  string
    99  	SubordinateTo []string
   100  	Units         map[string]UnitStatus
   101  	Status        AgentStatus
   102  }
   103  
   104  // UnitStatusHistory holds a slice of statuses.
   105  type UnitStatusHistory struct {
   106  	Statuses []AgentStatus
   107  }
   108  
   109  // UnitStatus holds status info about a unit.
   110  type UnitStatus struct {
   111  	// UnitAgent holds the status for a unit's agent.
   112  	UnitAgent AgentStatus
   113  
   114  	// Workload holds the status for a unit's workload
   115  	Workload AgentStatus
   116  
   117  	// Until Juju 2.0, we need to continue to return legacy agent state values
   118  	// as top level struct attributes when the "FullStatus" API is called.
   119  	AgentState     params.Status
   120  	AgentStateInfo string
   121  	AgentVersion   string
   122  	Life           string
   123  	Err            error
   124  
   125  	Machine       string
   126  	OpenedPorts   []string
   127  	PublicAddress string
   128  	Charm         string
   129  	Subordinates  map[string]UnitStatus
   130  }
   131  
   132  // RelationStatus holds status info about a relation.
   133  type RelationStatus struct {
   134  	Id        int
   135  	Key       string
   136  	Interface string
   137  	Scope     charm.RelationScope
   138  	Endpoints []EndpointStatus
   139  }
   140  
   141  // EndpointStatus holds status info about a single endpoint
   142  type EndpointStatus struct {
   143  	ServiceName string
   144  	Name        string
   145  	Role        charm.RelationRole
   146  	Subordinate bool
   147  }
   148  
   149  func (epStatus *EndpointStatus) String() string {
   150  	return epStatus.ServiceName + ":" + epStatus.Name
   151  }
   152  
   153  // NetworkStatus holds status info about a network.
   154  type NetworkStatus struct {
   155  	Err        error
   156  	ProviderId network.Id
   157  	CIDR       string
   158  	VLANTag    int
   159  }
   160  
   161  // Status holds information about the status of a juju environment.
   162  type Status struct {
   163  	EnvironmentName string
   164  	Machines        map[string]MachineStatus
   165  	Services        map[string]ServiceStatus
   166  	Networks        map[string]NetworkStatus
   167  	Relations       []RelationStatus
   168  }
   169  
   170  // Status returns the status of the juju environment.
   171  func (c *Client) Status(patterns []string) (*Status, error) {
   172  	var result Status
   173  	p := params.StatusParams{Patterns: patterns}
   174  	if err := c.facade.FacadeCall("FullStatus", p, &result); err != nil {
   175  		return nil, err
   176  	}
   177  	return &result, nil
   178  }
   179  
   180  // UnitStatusHistory retrieves the last <size> results of <kind:combined|agent|workload> status
   181  // for <unitName> unit
   182  func (c *Client) UnitStatusHistory(kind params.HistoryKind, unitName string, size int) (*UnitStatusHistory, error) {
   183  	var results UnitStatusHistory
   184  	args := params.StatusHistory{
   185  		Kind: kind,
   186  		Size: size,
   187  		Name: unitName,
   188  	}
   189  	err := c.facade.FacadeCall("UnitStatusHistory", args, &results)
   190  	if err != nil {
   191  		if params.IsCodeNotImplemented(err) {
   192  			return &UnitStatusHistory{}, errors.NotImplementedf("UnitStatusHistory")
   193  		}
   194  		return &UnitStatusHistory{}, errors.Trace(err)
   195  	}
   196  	return &results, nil
   197  }
   198  
   199  // LegacyMachineStatus holds just the instance-id of a machine.
   200  type LegacyMachineStatus struct {
   201  	InstanceId string // Not type instance.Id just to match original api.
   202  }
   203  
   204  // LegacyStatus holds minimal information on the status of a juju environment.
   205  type LegacyStatus struct {
   206  	Machines map[string]LegacyMachineStatus
   207  }
   208  
   209  // LegacyStatus is a stub version of Status that 1.16 introduced. Should be
   210  // removed along with structs when api versioning makes it safe to do so.
   211  func (c *Client) LegacyStatus() (*LegacyStatus, error) {
   212  	var result LegacyStatus
   213  	if err := c.facade.FacadeCall("Status", nil, &result); err != nil {
   214  		return nil, err
   215  	}
   216  	return &result, nil
   217  }
   218  
   219  // ServiceSet sets configuration options on a service.
   220  func (c *Client) ServiceSet(service string, options map[string]string) error {
   221  	p := params.ServiceSet{
   222  		ServiceName: service,
   223  		Options:     options,
   224  	}
   225  	// TODO(Nate): Put this back to ServiceSet when the GUI stops expecting
   226  	// ServiceSet to unset values set to an empty string.
   227  	return c.facade.FacadeCall("NewServiceSetForClientAPI", p, nil)
   228  }
   229  
   230  // ServiceUnset resets configuration options on a service.
   231  func (c *Client) ServiceUnset(service string, options []string) error {
   232  	p := params.ServiceUnset{
   233  		ServiceName: service,
   234  		Options:     options,
   235  	}
   236  	return c.facade.FacadeCall("ServiceUnset", p, nil)
   237  }
   238  
   239  // Resolved clears errors on a unit.
   240  func (c *Client) Resolved(unit string, retry bool) error {
   241  	p := params.Resolved{
   242  		UnitName: unit,
   243  		Retry:    retry,
   244  	}
   245  	return c.facade.FacadeCall("Resolved", p, nil)
   246  }
   247  
   248  // RetryProvisioning updates the provisioning status of a machine allowing the
   249  // provisioner to retry.
   250  func (c *Client) RetryProvisioning(machines ...names.MachineTag) ([]params.ErrorResult, error) {
   251  	p := params.Entities{}
   252  	p.Entities = make([]params.Entity, len(machines))
   253  	for i, machine := range machines {
   254  		p.Entities[i] = params.Entity{Tag: machine.String()}
   255  	}
   256  	var results params.ErrorResults
   257  	err := c.facade.FacadeCall("RetryProvisioning", p, &results)
   258  	return results.Results, err
   259  }
   260  
   261  // PublicAddress returns the public address of the specified
   262  // machine or unit. For a machine, target is an id not a tag.
   263  func (c *Client) PublicAddress(target string) (string, error) {
   264  	var results params.PublicAddressResults
   265  	p := params.PublicAddress{Target: target}
   266  	err := c.facade.FacadeCall("PublicAddress", p, &results)
   267  	return results.PublicAddress, err
   268  }
   269  
   270  // PrivateAddress returns the private address of the specified
   271  // machine or unit.
   272  func (c *Client) PrivateAddress(target string) (string, error) {
   273  	var results params.PrivateAddressResults
   274  	p := params.PrivateAddress{Target: target}
   275  	err := c.facade.FacadeCall("PrivateAddress", p, &results)
   276  	return results.PrivateAddress, err
   277  }
   278  
   279  // ServiceSetYAML sets configuration options on a service
   280  // given options in YAML format.
   281  func (c *Client) ServiceSetYAML(service string, yaml string) error {
   282  	p := params.ServiceSetYAML{
   283  		ServiceName: service,
   284  		Config:      yaml,
   285  	}
   286  	return c.facade.FacadeCall("ServiceSetYAML", p, nil)
   287  }
   288  
   289  // ServiceGet returns the configuration for the named service.
   290  func (c *Client) ServiceGet(service string) (*params.ServiceGetResults, error) {
   291  	var results params.ServiceGetResults
   292  	params := params.ServiceGet{ServiceName: service}
   293  	err := c.facade.FacadeCall("ServiceGet", params, &results)
   294  	return &results, err
   295  }
   296  
   297  // AddRelation adds a relation between the specified endpoints and returns the relation info.
   298  func (c *Client) AddRelation(endpoints ...string) (*params.AddRelationResults, error) {
   299  	var addRelRes params.AddRelationResults
   300  	params := params.AddRelation{Endpoints: endpoints}
   301  	err := c.facade.FacadeCall("AddRelation", params, &addRelRes)
   302  	return &addRelRes, err
   303  }
   304  
   305  // DestroyRelation removes the relation between the specified endpoints.
   306  func (c *Client) DestroyRelation(endpoints ...string) error {
   307  	params := params.DestroyRelation{Endpoints: endpoints}
   308  	return c.facade.FacadeCall("DestroyRelation", params, nil)
   309  }
   310  
   311  // ServiceCharmRelations returns the service's charms relation names.
   312  func (c *Client) ServiceCharmRelations(service string) ([]string, error) {
   313  	var results params.ServiceCharmRelationsResults
   314  	params := params.ServiceCharmRelations{ServiceName: service}
   315  	err := c.facade.FacadeCall("ServiceCharmRelations", params, &results)
   316  	return results.CharmRelations, err
   317  }
   318  
   319  // AddMachines1dot18 adds new machines with the supplied parameters.
   320  //
   321  // TODO(axw) 2014-04-11 #XXX
   322  // This exists for backwards compatibility;
   323  // We cannot remove this code while clients > 1.20 need to talk to 1.18
   324  // servers (which is something we need for an undetermined amount of time).
   325  func (c *Client) AddMachines1dot18(machineParams []params.AddMachineParams) ([]params.AddMachinesResult, error) {
   326  	args := params.AddMachines{
   327  		MachineParams: machineParams,
   328  	}
   329  	results := new(params.AddMachinesResults)
   330  	err := c.facade.FacadeCall("AddMachines", args, results)
   331  	return results.Machines, err
   332  }
   333  
   334  // AddMachines adds new machines with the supplied parameters.
   335  func (c *Client) AddMachines(machineParams []params.AddMachineParams) ([]params.AddMachinesResult, error) {
   336  	args := params.AddMachines{
   337  		MachineParams: machineParams,
   338  	}
   339  	results := new(params.AddMachinesResults)
   340  	err := c.facade.FacadeCall("AddMachinesV2", args, results)
   341  	return results.Machines, err
   342  }
   343  
   344  // ProvisioningScript returns a shell script that, when run,
   345  // provisions a machine agent on the machine executing the script.
   346  func (c *Client) ProvisioningScript(args params.ProvisioningScriptParams) (script string, err error) {
   347  	var result params.ProvisioningScriptResult
   348  	if err = c.facade.FacadeCall("ProvisioningScript", args, &result); err != nil {
   349  		return "", err
   350  	}
   351  	return result.Script, nil
   352  }
   353  
   354  // DestroyMachines removes a given set of machines.
   355  func (c *Client) DestroyMachines(machines ...string) error {
   356  	params := params.DestroyMachines{MachineNames: machines}
   357  	return c.facade.FacadeCall("DestroyMachines", params, nil)
   358  }
   359  
   360  // ForceDestroyMachines removes a given set of machines and all associated units.
   361  func (c *Client) ForceDestroyMachines(machines ...string) error {
   362  	params := params.DestroyMachines{Force: true, MachineNames: machines}
   363  	return c.facade.FacadeCall("DestroyMachines", params, nil)
   364  }
   365  
   366  // ServiceExpose changes the juju-managed firewall to expose any ports that
   367  // were also explicitly marked by units as open.
   368  func (c *Client) ServiceExpose(service string) error {
   369  	params := params.ServiceExpose{ServiceName: service}
   370  	return c.facade.FacadeCall("ServiceExpose", params, nil)
   371  }
   372  
   373  // ServiceUnexpose changes the juju-managed firewall to unexpose any ports that
   374  // were also explicitly marked by units as open.
   375  func (c *Client) ServiceUnexpose(service string) error {
   376  	params := params.ServiceUnexpose{ServiceName: service}
   377  	return c.facade.FacadeCall("ServiceUnexpose", params, nil)
   378  }
   379  
   380  // ServiceDeployWithNetworks works exactly like ServiceDeploy, but
   381  // allows the specification of requested networks that must be present
   382  // on the machines where the service is deployed. Another way to specify
   383  // networks to include/exclude is using constraints.
   384  func (c *Client) ServiceDeployWithNetworks(
   385  	charmURL string,
   386  	serviceName string,
   387  	numUnits int,
   388  	configYAML string,
   389  	cons constraints.Value,
   390  	toMachineSpec string,
   391  	networks []string,
   392  ) error {
   393  	params := params.ServiceDeploy{
   394  		ServiceName:   serviceName,
   395  		CharmUrl:      charmURL,
   396  		NumUnits:      numUnits,
   397  		ConfigYAML:    configYAML,
   398  		Constraints:   cons,
   399  		ToMachineSpec: toMachineSpec,
   400  		Networks:      networks,
   401  	}
   402  	return c.facade.FacadeCall("ServiceDeployWithNetworks", params, nil)
   403  }
   404  
   405  // ServiceDeploy obtains the charm, either locally or from the charm store,
   406  // and deploys it.
   407  func (c *Client) ServiceDeploy(charmURL string, serviceName string, numUnits int, configYAML string, cons constraints.Value, toMachineSpec string) error {
   408  	params := params.ServiceDeploy{
   409  		ServiceName:   serviceName,
   410  		CharmUrl:      charmURL,
   411  		NumUnits:      numUnits,
   412  		ConfigYAML:    configYAML,
   413  		Constraints:   cons,
   414  		ToMachineSpec: toMachineSpec,
   415  	}
   416  	return c.facade.FacadeCall("ServiceDeploy", params, nil)
   417  }
   418  
   419  // ServiceUpdate updates the service attributes, including charm URL,
   420  // minimum number of units, settings and constraints.
   421  // TODO(frankban) deprecate redundant API calls that this supercedes.
   422  func (c *Client) ServiceUpdate(args params.ServiceUpdate) error {
   423  	return c.facade.FacadeCall("ServiceUpdate", args, nil)
   424  }
   425  
   426  // ServiceSetCharm sets the charm for a given service.
   427  func (c *Client) ServiceSetCharm(serviceName string, charmUrl string, force bool) error {
   428  	args := params.ServiceSetCharm{
   429  		ServiceName: serviceName,
   430  		CharmUrl:    charmUrl,
   431  		Force:       force,
   432  	}
   433  	return c.facade.FacadeCall("ServiceSetCharm", args, nil)
   434  }
   435  
   436  // ServiceGetCharmURL returns the charm URL the given service is
   437  // running at present.
   438  func (c *Client) ServiceGetCharmURL(serviceName string) (*charm.URL, error) {
   439  	result := new(params.StringResult)
   440  	args := params.ServiceGet{ServiceName: serviceName}
   441  	err := c.facade.FacadeCall("ServiceGetCharmURL", args, &result)
   442  	if err != nil {
   443  		return nil, err
   444  	}
   445  	return charm.ParseURL(result.Result)
   446  }
   447  
   448  // AddServiceUnits adds a given number of units to a service.
   449  func (c *Client) AddServiceUnits(service string, numUnits int, machineSpec string) ([]string, error) {
   450  	args := params.AddServiceUnits{
   451  		ServiceName:   service,
   452  		NumUnits:      numUnits,
   453  		ToMachineSpec: machineSpec,
   454  	}
   455  	results := new(params.AddServiceUnitsResults)
   456  	err := c.facade.FacadeCall("AddServiceUnits", args, results)
   457  	return results.Units, err
   458  }
   459  
   460  // DestroyServiceUnits decreases the number of units dedicated to a service.
   461  func (c *Client) DestroyServiceUnits(unitNames ...string) error {
   462  	params := params.DestroyServiceUnits{unitNames}
   463  	return c.facade.FacadeCall("DestroyServiceUnits", params, nil)
   464  }
   465  
   466  // ServiceDestroy destroys a given service.
   467  func (c *Client) ServiceDestroy(service string) error {
   468  	params := params.ServiceDestroy{
   469  		ServiceName: service,
   470  	}
   471  	return c.facade.FacadeCall("ServiceDestroy", params, nil)
   472  }
   473  
   474  // GetServiceConstraints returns the constraints for the given service.
   475  func (c *Client) GetServiceConstraints(service string) (constraints.Value, error) {
   476  	results := new(params.GetConstraintsResults)
   477  	err := c.facade.FacadeCall("GetServiceConstraints", params.GetServiceConstraints{service}, results)
   478  	return results.Constraints, err
   479  }
   480  
   481  // GetEnvironmentConstraints returns the constraints for the environment.
   482  func (c *Client) GetEnvironmentConstraints() (constraints.Value, error) {
   483  	results := new(params.GetConstraintsResults)
   484  	err := c.facade.FacadeCall("GetEnvironmentConstraints", nil, results)
   485  	return results.Constraints, err
   486  }
   487  
   488  // SetServiceConstraints specifies the constraints for the given service.
   489  func (c *Client) SetServiceConstraints(service string, constraints constraints.Value) error {
   490  	params := params.SetConstraints{
   491  		ServiceName: service,
   492  		Constraints: constraints,
   493  	}
   494  	return c.facade.FacadeCall("SetServiceConstraints", params, nil)
   495  }
   496  
   497  // SetEnvironmentConstraints specifies the constraints for the environment.
   498  func (c *Client) SetEnvironmentConstraints(constraints constraints.Value) error {
   499  	params := params.SetConstraints{
   500  		Constraints: constraints,
   501  	}
   502  	return c.facade.FacadeCall("SetEnvironmentConstraints", params, nil)
   503  }
   504  
   505  // CharmInfo holds information about a charm.
   506  type CharmInfo struct {
   507  	Revision int
   508  	URL      string
   509  	Config   *charm.Config
   510  	Meta     *charm.Meta
   511  	Actions  *charm.Actions
   512  }
   513  
   514  // CharmInfo returns information about the requested charm.
   515  func (c *Client) CharmInfo(charmURL string) (*CharmInfo, error) {
   516  	args := params.CharmInfo{CharmURL: charmURL}
   517  	info := new(CharmInfo)
   518  	if err := c.facade.FacadeCall("CharmInfo", args, info); err != nil {
   519  		return nil, err
   520  	}
   521  	return info, nil
   522  }
   523  
   524  // EnvironmentInfo holds information about the Juju environment.
   525  type EnvironmentInfo struct {
   526  	DefaultSeries string
   527  	ProviderType  string
   528  	Name          string
   529  	UUID          string
   530  	ServerUUID    string
   531  }
   532  
   533  // EnvironmentInfo returns details about the Juju environment.
   534  func (c *Client) EnvironmentInfo() (*EnvironmentInfo, error) {
   535  	info := new(EnvironmentInfo)
   536  	err := c.facade.FacadeCall("EnvironmentInfo", nil, info)
   537  	return info, err
   538  }
   539  
   540  // EnvironmentUUID returns the environment UUID from the client connection.
   541  func (c *Client) EnvironmentUUID() string {
   542  	tag, err := c.st.EnvironTag()
   543  	if err != nil {
   544  		logger.Warningf("environ tag not an environ: %v", err)
   545  		return ""
   546  	}
   547  	return tag.Id()
   548  }
   549  
   550  // ShareEnvironment allows the given users access to the environment.
   551  func (c *Client) ShareEnvironment(users ...names.UserTag) error {
   552  	var args params.ModifyEnvironUsers
   553  	for _, user := range users {
   554  		if &user != nil {
   555  			args.Changes = append(args.Changes, params.ModifyEnvironUser{
   556  				UserTag: user.String(),
   557  				Action:  params.AddEnvUser,
   558  			})
   559  		}
   560  	}
   561  
   562  	var result params.ErrorResults
   563  	err := c.facade.FacadeCall("ShareEnvironment", args, &result)
   564  	if err != nil {
   565  		return errors.Trace(err)
   566  	}
   567  
   568  	for i, r := range result.Results {
   569  		if r.Error != nil && r.Error.Code == params.CodeAlreadyExists {
   570  			logger.Warningf("environment is already shared with %s", users[i].Username())
   571  			result.Results[i].Error = nil
   572  		}
   573  	}
   574  	return result.Combine()
   575  }
   576  
   577  // EnvironmentUserInfo returns information on all users in the environment.
   578  func (c *Client) EnvironmentUserInfo() ([]params.EnvUserInfo, error) {
   579  	var results params.EnvUserInfoResults
   580  	err := c.facade.FacadeCall("EnvUserInfo", nil, &results)
   581  	if err != nil {
   582  		return nil, errors.Trace(err)
   583  	}
   584  
   585  	info := []params.EnvUserInfo{}
   586  	for i, result := range results.Results {
   587  		if result.Result == nil {
   588  			return nil, errors.Errorf("unexpected nil result at position %d", i)
   589  		}
   590  		info = append(info, *result.Result)
   591  	}
   592  	return info, nil
   593  }
   594  
   595  // UnshareEnvironment removes access to the environment for the given users.
   596  func (c *Client) UnshareEnvironment(users ...names.UserTag) error {
   597  	var args params.ModifyEnvironUsers
   598  	for _, user := range users {
   599  		if &user != nil {
   600  			args.Changes = append(args.Changes, params.ModifyEnvironUser{
   601  				UserTag: user.String(),
   602  				Action:  params.RemoveEnvUser,
   603  			})
   604  		}
   605  	}
   606  
   607  	var result params.ErrorResults
   608  	err := c.facade.FacadeCall("ShareEnvironment", args, &result)
   609  	if err != nil {
   610  		return errors.Trace(err)
   611  	}
   612  
   613  	for i, r := range result.Results {
   614  		if r.Error != nil && r.Error.Code == params.CodeNotFound {
   615  			logger.Warningf("environment was not previously shared with user %s", users[i].Username())
   616  			result.Results[i].Error = nil
   617  		}
   618  	}
   619  	return result.Combine()
   620  }
   621  
   622  // WatchAll holds the id of the newly-created AllWatcher.
   623  type WatchAll struct {
   624  	AllWatcherId string
   625  }
   626  
   627  // WatchAll returns an AllWatcher, from which you can request the Next
   628  // collection of Deltas.
   629  func (c *Client) WatchAll() (*AllWatcher, error) {
   630  	info := new(WatchAll)
   631  	if err := c.facade.FacadeCall("WatchAll", nil, info); err != nil {
   632  		return nil, err
   633  	}
   634  	return newAllWatcher(c.st, &info.AllWatcherId), nil
   635  }
   636  
   637  // GetAnnotations returns annotations that have been set on the given entity.
   638  // This API is now deprecated - "Annotations" client should be used instead.
   639  // TODO(anastasiamac) remove for Juju 2.x
   640  func (c *Client) GetAnnotations(tag string) (map[string]string, error) {
   641  	args := params.GetAnnotations{tag}
   642  	ann := new(params.GetAnnotationsResults)
   643  	err := c.facade.FacadeCall("GetAnnotations", args, ann)
   644  	return ann.Annotations, err
   645  }
   646  
   647  // SetAnnotations sets the annotation pairs on the given entity.
   648  // Currently annotations are supported on machines, services,
   649  // units and the environment itself.
   650  // This API is now deprecated - "Annotations" client should be used instead.
   651  // TODO(anastasiamac) remove for Juju 2.x
   652  func (c *Client) SetAnnotations(tag string, pairs map[string]string) error {
   653  	args := params.SetAnnotations{tag, pairs}
   654  	return c.facade.FacadeCall("SetAnnotations", args, nil)
   655  }
   656  
   657  // Close closes the Client's underlying State connection
   658  // Client is unique among the api.State facades in closing its own State
   659  // connection, but it is conventional to use a Client object without any access
   660  // to its underlying state connection.
   661  func (c *Client) Close() error {
   662  	return c.st.Close()
   663  }
   664  
   665  // EnvironmentGet returns all environment settings.
   666  func (c *Client) EnvironmentGet() (map[string]interface{}, error) {
   667  	result := params.EnvironmentConfigResults{}
   668  	err := c.facade.FacadeCall("EnvironmentGet", nil, &result)
   669  	return result.Config, err
   670  }
   671  
   672  // EnvironmentSet sets the given key-value pairs in the environment.
   673  func (c *Client) EnvironmentSet(config map[string]interface{}) error {
   674  	args := params.EnvironmentSet{Config: config}
   675  	return c.facade.FacadeCall("EnvironmentSet", args, nil)
   676  }
   677  
   678  // EnvironmentUnset sets the given key-value pairs in the environment.
   679  func (c *Client) EnvironmentUnset(keys ...string) error {
   680  	args := params.EnvironmentUnset{Keys: keys}
   681  	return c.facade.FacadeCall("EnvironmentUnset", args, nil)
   682  }
   683  
   684  // SetEnvironAgentVersion sets the environment agent-version setting
   685  // to the given value.
   686  func (c *Client) SetEnvironAgentVersion(version version.Number) error {
   687  	args := params.SetEnvironAgentVersion{Version: version}
   688  	return c.facade.FacadeCall("SetEnvironAgentVersion", args, nil)
   689  }
   690  
   691  // AbortCurrentUpgrade aborts and archives the current upgrade
   692  // synchronisation record, if any.
   693  func (c *Client) AbortCurrentUpgrade() error {
   694  	return c.facade.FacadeCall("AbortCurrentUpgrade", nil, nil)
   695  }
   696  
   697  // FindTools returns a List containing all tools matching the specified parameters.
   698  func (c *Client) FindTools(
   699  	majorVersion, minorVersion int,
   700  	series, arch string,
   701  ) (result params.FindToolsResult, err error) {
   702  	args := params.FindToolsParams{
   703  		MajorVersion: majorVersion,
   704  		MinorVersion: minorVersion,
   705  		Arch:         arch,
   706  		Series:       series,
   707  	}
   708  	err = c.facade.FacadeCall("FindTools", args, &result)
   709  	return result, err
   710  }
   711  
   712  // RunOnAllMachines runs the command on all the machines with the specified
   713  // timeout.
   714  func (c *Client) RunOnAllMachines(commands string, timeout time.Duration) ([]params.RunResult, error) {
   715  	var results params.RunResults
   716  	args := params.RunParams{Commands: commands, Timeout: timeout}
   717  	err := c.facade.FacadeCall("RunOnAllMachines", args, &results)
   718  	return results.Results, err
   719  }
   720  
   721  // Run the Commands specified on the machines identified through the ids
   722  // provided in the machines, services and units slices.
   723  func (c *Client) Run(run params.RunParams) ([]params.RunResult, error) {
   724  	var results params.RunResults
   725  	err := c.facade.FacadeCall("Run", run, &results)
   726  	return results.Results, err
   727  }
   728  
   729  // DestroyEnvironment puts the environment into a "dying" state,
   730  // and removes all non-manager machine instances. DestroyEnvironment
   731  // will fail if there are any manually-provisioned non-manager machines
   732  // in state.
   733  func (c *Client) DestroyEnvironment() error {
   734  	return c.facade.FacadeCall("DestroyEnvironment", nil, nil)
   735  }
   736  
   737  // AddLocalCharm prepares the given charm with a local: schema in its
   738  // URL, and uploads it via the API server, returning the assigned
   739  // charm URL. If the API server does not support charm uploads, an
   740  // error satisfying params.IsCodeNotImplemented() is returned.
   741  func (c *Client) AddLocalCharm(curl *charm.URL, ch charm.Charm) (*charm.URL, error) {
   742  	if curl.Schema != "local" {
   743  		return nil, errors.Errorf("expected charm URL with local: schema, got %q", curl.String())
   744  	}
   745  	// Package the charm for uploading.
   746  	var archive *os.File
   747  	switch ch := ch.(type) {
   748  	case *charm.CharmDir:
   749  		var err error
   750  		if archive, err = ioutil.TempFile("", "charm"); err != nil {
   751  			return nil, errors.Annotate(err, "cannot create temp file")
   752  		}
   753  		defer os.Remove(archive.Name())
   754  		defer archive.Close()
   755  		if err := ch.ArchiveTo(archive); err != nil {
   756  			return nil, errors.Annotate(err, "cannot repackage charm")
   757  		}
   758  		if _, err := archive.Seek(0, 0); err != nil {
   759  			return nil, errors.Annotate(err, "cannot rewind packaged charm")
   760  		}
   761  	case *charm.CharmArchive:
   762  		var err error
   763  		if archive, err = os.Open(ch.Path); err != nil {
   764  			return nil, errors.Annotate(err, "cannot read charm archive")
   765  		}
   766  		defer archive.Close()
   767  	default:
   768  		return nil, errors.Errorf("unknown charm type %T", ch)
   769  	}
   770  
   771  	endPoint, err := c.apiEndpoint("charms", "series="+curl.Series)
   772  	if err != nil {
   773  		return nil, errors.Trace(err)
   774  	}
   775  
   776  	// wrap archive in a noopCloser to prevent the underlying transport closing
   777  	// the request body. This is neccessary to prevent a data race on the underlying
   778  	// *os.File as the http transport _may_ issue Close once the body is sent, or it
   779  	// may not if there is an error.
   780  	noop := &noopCloser{archive}
   781  	req, err := http.NewRequest("POST", endPoint, noop)
   782  	if err != nil {
   783  		return nil, errors.Annotate(err, "cannot create upload request")
   784  	}
   785  	req.SetBasicAuth(c.st.tag, c.st.password)
   786  	req.Header.Set("Content-Type", "application/zip")
   787  
   788  	// Send the request.
   789  
   790  	// BUG(dimitern) 2013-12-17 bug #1261780
   791  	// Due to issues with go 1.1.2, fixed later, we cannot use a
   792  	// regular TLS client with the CACert here, because we get "x509:
   793  	// cannot validate certificate for 127.0.0.1 because it doesn't
   794  	// contain any IP SANs". Once we use a later go version, this
   795  	// should be changed to connect to the API server with a regular
   796  	// HTTP+TLS enabled client, using the CACert (possily cached, like
   797  	// the tag and password) passed in api.Open()'s info argument.
   798  	resp, err := utils.GetNonValidatingHTTPClient().Do(req)
   799  	if err != nil {
   800  		return nil, errors.Annotate(err, "cannot upload charm")
   801  	}
   802  	defer resp.Body.Close()
   803  
   804  	// Now parse the response & return.
   805  	body, err := ioutil.ReadAll(resp.Body)
   806  	if err != nil {
   807  		return nil, errors.Annotate(err, "cannot read charm upload response")
   808  	}
   809  	if resp.StatusCode != http.StatusOK {
   810  		return nil, errors.Errorf("charm upload failed: %v (%s)", resp.StatusCode, bytes.TrimSpace(body))
   811  	}
   812  
   813  	var jsonResponse params.CharmsResponse
   814  	if err := json.Unmarshal(body, &jsonResponse); err != nil {
   815  		return nil, errors.Annotate(err, "cannot unmarshal upload response")
   816  	}
   817  	if jsonResponse.Error != "" {
   818  		return nil, errors.Errorf("error uploading charm: %v", jsonResponse.Error)
   819  	}
   820  	return charm.MustParseURL(jsonResponse.CharmURL), nil
   821  }
   822  
   823  // noopCloser implements io.ReadCloser, but does not close the underlying io.ReadCloser.
   824  // This is necessary to ensure the ownership of io.ReadCloser implementations that are
   825  // passed to the net/http Transport which may (under some circumstances), call Close on
   826  // the body passed to a request.
   827  type noopCloser struct {
   828  	io.ReadCloser
   829  }
   830  
   831  func (n *noopCloser) Close() error {
   832  
   833  	// do not propogate the Close method to the underlying ReadCloser.
   834  	return nil
   835  }
   836  
   837  func (c *Client) apiEndpoint(destination, query string) (string, error) {
   838  	root, err := c.apiRoot()
   839  	if err != nil {
   840  		return "", errors.Trace(err)
   841  	}
   842  
   843  	upURL := url.URL{
   844  		Scheme:   c.st.serverScheme,
   845  		Host:     c.st.Addr(),
   846  		Path:     path.Join(root, destination),
   847  		RawQuery: query,
   848  	}
   849  	return upURL.String(), nil
   850  }
   851  
   852  func (c *Client) apiRoot() (string, error) {
   853  	var apiRoot string
   854  	if _, err := c.st.ServerTag(); err == nil {
   855  		envTag, err := c.st.EnvironTag()
   856  		if err != nil {
   857  			return "", errors.Annotate(err, "cannot get API endpoint address")
   858  		}
   859  
   860  		apiRoot = fmt.Sprintf("/environment/%s/", envTag.Id())
   861  	} else {
   862  		// If the server tag is not set, then the agent version is < 1.23. We
   863  		// use the old API endpoint for backwards compatibility.
   864  		apiRoot = "/"
   865  	}
   866  	return apiRoot, nil
   867  }
   868  
   869  // AddCharm adds the given charm URL (which must include revision) to
   870  // the environment, if it does not exist yet. Local charms are not
   871  // supported, only charm store URLs. See also AddLocalCharm() in the
   872  // client-side API.
   873  //
   874  // If the AddCharm API call fails because of an authorization error
   875  // when retrieving the charm from the charm store, an error
   876  // satisfying params.IsCodeUnauthorized will be returned.
   877  func (c *Client) AddCharm(curl *charm.URL) error {
   878  	args := params.CharmURL{
   879  		URL: curl.String(),
   880  	}
   881  	return c.facade.FacadeCall("AddCharm", args, nil)
   882  }
   883  
   884  // AddCharmWithAuthorization is like AddCharm except it also provides
   885  // the given charmstore macaroon for the juju server to use when
   886  // obtaining the charm from the charm store. The macaroon is
   887  // conventionally obtained from the /delegatable-macaroon endpoint in
   888  // the charm store.
   889  //
   890  // If the AddCharmWithAuthorization API call fails because of an
   891  // authorization error when retrieving the charm from the charm store,
   892  // an error satisfying params.IsCodeUnauthorized will be returned.
   893  func (c *Client) AddCharmWithAuthorization(curl *charm.URL, csMac *macaroon.Macaroon) error {
   894  	args := params.AddCharmWithAuthorization{
   895  		URL:                curl.String(),
   896  		CharmStoreMacaroon: csMac,
   897  	}
   898  	return c.facade.FacadeCall("AddCharmWithAuthorization", args, nil)
   899  }
   900  
   901  // ResolveCharm resolves the best available charm URLs with series, for charm
   902  // locations without a series specified.
   903  func (c *Client) ResolveCharm(ref *charm.Reference) (*charm.URL, error) {
   904  	args := params.ResolveCharms{References: []charm.Reference{*ref}}
   905  	result := new(params.ResolveCharmResults)
   906  	if err := c.facade.FacadeCall("ResolveCharms", args, result); err != nil {
   907  		return nil, err
   908  	}
   909  	if len(result.URLs) == 0 {
   910  		return nil, errors.New("unexpected empty response")
   911  	}
   912  	urlInfo := result.URLs[0]
   913  	if urlInfo.Error != "" {
   914  		return nil, errors.New(urlInfo.Error)
   915  	}
   916  	return urlInfo.URL, nil
   917  }
   918  
   919  // UploadTools uploads tools at the specified location to the API server over HTTPS.
   920  func (c *Client) UploadTools(r io.Reader, vers version.Binary, additionalSeries ...string) (*tools.Tools, error) {
   921  	// Prepare the upload request.
   922  	query := fmt.Sprintf("binaryVersion=%s&series=%s",
   923  		vers,
   924  		strings.Join(additionalSeries, ","),
   925  	)
   926  
   927  	endPoint, err := c.apiEndpoint("tools", query)
   928  	if err != nil {
   929  		return nil, errors.Trace(err)
   930  	}
   931  
   932  	req, err := http.NewRequest("POST", endPoint, r)
   933  	if err != nil {
   934  		return nil, errors.Annotate(err, "cannot create upload request")
   935  	}
   936  	req.SetBasicAuth(c.st.tag, c.st.password)
   937  	req.Header.Set("Content-Type", "application/x-tar-gz")
   938  
   939  	// Send the request.
   940  
   941  	// BUG(dimitern) 2013-12-17 bug #1261780
   942  	// Due to issues with go 1.1.2, fixed later, we cannot use a
   943  	// regular TLS client with the CACert here, because we get "x509:
   944  	// cannot validate certificate for 127.0.0.1 because it doesn't
   945  	// contain any IP SANs". Once we use a later go version, this
   946  	// should be changed to connect to the API server with a regular
   947  	// HTTP+TLS enabled client, using the CACert (possily cached, like
   948  	// the tag and password) passed in api.Open()'s info argument.
   949  	resp, err := utils.GetNonValidatingHTTPClient().Do(req)
   950  	if err != nil {
   951  		return nil, errors.Annotate(err, "cannot upload tools")
   952  	}
   953  	defer resp.Body.Close()
   954  
   955  	// Now parse the response & return.
   956  	body, err := ioutil.ReadAll(resp.Body)
   957  	if err != nil {
   958  		return nil, errors.Annotate(err, "cannot read tools upload response")
   959  	}
   960  	if resp.StatusCode != http.StatusOK {
   961  		message := fmt.Sprintf("%s", bytes.TrimSpace(body))
   962  		if resp.StatusCode == http.StatusBadRequest && strings.Contains(message, params.CodeOperationBlocked) {
   963  			// Operation Blocked errors must contain correct error code and message.
   964  			return nil, &params.Error{Code: params.CodeOperationBlocked, Message: message}
   965  		}
   966  		return nil, errors.Errorf("tools upload failed: %v (%s)", resp.StatusCode, message)
   967  	}
   968  
   969  	var jsonResponse params.ToolsResult
   970  	if err := json.Unmarshal(body, &jsonResponse); err != nil {
   971  		return nil, errors.Annotate(err, "cannot unmarshal upload response")
   972  	}
   973  	if err := jsonResponse.Error; err != nil {
   974  		return nil, errors.Annotate(err, "error uploading tools")
   975  	}
   976  	return jsonResponse.Tools, nil
   977  }
   978  
   979  // APIHostPorts returns a slice of network.HostPort for each API server.
   980  func (c *Client) APIHostPorts() ([][]network.HostPort, error) {
   981  	var result params.APIHostPortsResult
   982  	if err := c.facade.FacadeCall("APIHostPorts", nil, &result); err != nil {
   983  		return nil, err
   984  	}
   985  	return result.NetworkHostsPorts(), nil
   986  }
   987  
   988  // EnsureAvailability ensures the availability of Juju state servers.
   989  // DEPRECATED: remove when we stop supporting 1.20 and earlier servers.
   990  // This API is now on the HighAvailability facade.
   991  func (c *Client) EnsureAvailability(numStateServers int, cons constraints.Value, series string) (params.StateServersChanges, error) {
   992  	var results params.StateServersChangeResults
   993  	envTag, err := c.st.EnvironTag()
   994  	if err != nil {
   995  		return params.StateServersChanges{}, errors.Trace(err)
   996  	}
   997  	arg := params.StateServersSpecs{
   998  		Specs: []params.StateServersSpec{{
   999  			EnvironTag:      envTag.String(),
  1000  			NumStateServers: numStateServers,
  1001  			Constraints:     cons,
  1002  			Series:          series,
  1003  		}}}
  1004  	err = c.facade.FacadeCall("EnsureAvailability", arg, &results)
  1005  	if err != nil {
  1006  		return params.StateServersChanges{}, err
  1007  	}
  1008  	if len(results.Results) != 1 {
  1009  		return params.StateServersChanges{}, errors.Errorf("expected 1 result, got %d", len(results.Results))
  1010  	}
  1011  	result := results.Results[0]
  1012  	if result.Error != nil {
  1013  		return params.StateServersChanges{}, result.Error
  1014  	}
  1015  	return result.Result, nil
  1016  }
  1017  
  1018  // AgentVersion reports the version number of the api server.
  1019  func (c *Client) AgentVersion() (version.Number, error) {
  1020  	var result params.AgentVersionResult
  1021  	if err := c.facade.FacadeCall("AgentVersion", nil, &result); err != nil {
  1022  		return version.Number{}, err
  1023  	}
  1024  	return result.Version, nil
  1025  }
  1026  
  1027  // websocketDialConfig is called instead of websocket.DialConfig so we can
  1028  // override it in tests.
  1029  var websocketDialConfig = func(config *websocket.Config) (io.ReadCloser, error) {
  1030  	return websocket.DialConfig(config)
  1031  }
  1032  
  1033  // DebugLogParams holds parameters for WatchDebugLog that control the
  1034  // filtering of the log messages. If the structure is zero initialized, the
  1035  // entire log file is sent back starting from the end, and until the user
  1036  // closes the connection.
  1037  type DebugLogParams struct {
  1038  	// IncludeEntity lists entity tags to include in the response. Tags may
  1039  	// finish with a '*' to match a prefix e.g.: unit-mysql-*, machine-2. If
  1040  	// none are set, then all lines are considered included.
  1041  	IncludeEntity []string
  1042  	// IncludeModule lists logging modules to include in the response. If none
  1043  	// are set all modules are considered included.  If a module is specified,
  1044  	// all the submodules also match.
  1045  	IncludeModule []string
  1046  	// ExcludeEntity lists entity tags to exclude from the response. As with
  1047  	// IncludeEntity the values may finish with a '*'.
  1048  	ExcludeEntity []string
  1049  	// ExcludeModule lists logging modules to exclude from the resposne. If a
  1050  	// module is specified, all the submodules are also excluded.
  1051  	ExcludeModule []string
  1052  	// Limit defines the maximum number of lines to return. Once this many
  1053  	// have been sent, the socket is closed.  If zero, all filtered lines are
  1054  	// sent down the connection until the client closes the connection.
  1055  	Limit uint
  1056  	// Backlog tells the server to try to go back this many lines before
  1057  	// starting filtering. If backlog is zero and replay is false, then there
  1058  	// may be an initial delay until the next matching log message is written.
  1059  	Backlog uint
  1060  	// Level specifies the minimum logging level to be sent back in the response.
  1061  	Level loggo.Level
  1062  	// Replay tells the server to start at the start of the log file rather
  1063  	// than the end. If replay is true, backlog is ignored.
  1064  	Replay bool
  1065  }
  1066  
  1067  // WatchDebugLog returns a ReadCloser that the caller can read the log
  1068  // lines from. Only log lines that match the filtering specified in
  1069  // the DebugLogParams are returned. It returns an error that satisfies
  1070  // errors.IsNotImplemented when the API server does not support the
  1071  // end-point.
  1072  //
  1073  // TODO(dimitern) We already have errors.IsNotImplemented - why do we
  1074  // need to define a different error for this purpose here?
  1075  func (c *Client) WatchDebugLog(args DebugLogParams) (io.ReadCloser, error) {
  1076  	// The websocket connection just hangs if the server doesn't have the log
  1077  	// end point. So do a version check, as version was added at the same time
  1078  	// as the remote end point.
  1079  	_, err := c.AgentVersion()
  1080  	if err != nil {
  1081  		return nil, errors.NotSupportedf("WatchDebugLog")
  1082  	}
  1083  	// Prepare URL.
  1084  	attrs := url.Values{}
  1085  	if args.Replay {
  1086  		attrs.Set("replay", fmt.Sprint(args.Replay))
  1087  	}
  1088  	if args.Limit > 0 {
  1089  		attrs.Set("maxLines", fmt.Sprint(args.Limit))
  1090  	}
  1091  	if args.Backlog > 0 {
  1092  		attrs.Set("backlog", fmt.Sprint(args.Backlog))
  1093  	}
  1094  	if args.Level != loggo.UNSPECIFIED {
  1095  		attrs.Set("level", fmt.Sprint(args.Level))
  1096  	}
  1097  	attrs["includeEntity"] = args.IncludeEntity
  1098  	attrs["includeModule"] = args.IncludeModule
  1099  	attrs["excludeEntity"] = args.ExcludeEntity
  1100  	attrs["excludeModule"] = args.ExcludeModule
  1101  
  1102  	path := "/log"
  1103  	if _, ok := c.st.ServerVersion(); ok {
  1104  		// If the server version is set, then we know the server is capable of
  1105  		// serving debug log at the environment path. We also fully expect
  1106  		// that the server has returned a valid environment tag.
  1107  		envTag, err := c.st.EnvironTag()
  1108  		if err != nil {
  1109  			return nil, errors.Annotate(err, "very unexpected")
  1110  		}
  1111  		path = fmt.Sprintf("/environment/%s/log", envTag.Id())
  1112  	}
  1113  
  1114  	target := url.URL{
  1115  		Scheme:   "wss",
  1116  		Host:     c.st.addr,
  1117  		Path:     path,
  1118  		RawQuery: attrs.Encode(),
  1119  	}
  1120  	cfg, err := websocket.NewConfig(target.String(), "http://localhost/")
  1121  	cfg.Header = utils.BasicAuthHeader(c.st.tag, c.st.password)
  1122  	cfg.TlsConfig = &tls.Config{RootCAs: c.st.certPool, ServerName: "juju-apiserver"}
  1123  	connection, err := websocketDialConfig(cfg)
  1124  	if err != nil {
  1125  		return nil, err
  1126  	}
  1127  	// Read the initial error and translate to a real error.
  1128  	// Read up to the first new line character. We can't use bufio here as it
  1129  	// reads too much from the reader.
  1130  	line := make([]byte, 4096)
  1131  	n, err := connection.Read(line)
  1132  	if err != nil {
  1133  		return nil, errors.Annotate(err, "unable to read initial response")
  1134  	}
  1135  	line = line[0:n]
  1136  
  1137  	logger.Debugf("initial line: %q", line)
  1138  	var errResult params.ErrorResult
  1139  	err = json.Unmarshal(line, &errResult)
  1140  	if err != nil {
  1141  		return nil, errors.Annotate(err, "unable to unmarshal initial response")
  1142  	}
  1143  	if errResult.Error != nil {
  1144  		return nil, errResult.Error
  1145  	}
  1146  	return connection, nil
  1147  }