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

     1  // Copyright 2013, 2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package client
     5  
     6  import (
     7  	"fmt"
     8  	"strings"
     9  
    10  	"github.com/juju/errors"
    11  	"github.com/juju/loggo"
    12  	"github.com/juju/names"
    13  	"gopkg.in/juju/charm.v5"
    14  
    15  	"github.com/juju/juju/api"
    16  	"github.com/juju/juju/apiserver/common"
    17  	"github.com/juju/juju/apiserver/highavailability"
    18  	"github.com/juju/juju/apiserver/params"
    19  	"github.com/juju/juju/apiserver/service"
    20  	"github.com/juju/juju/environs/config"
    21  	"github.com/juju/juju/environs/manual"
    22  	"github.com/juju/juju/instance"
    23  	jjj "github.com/juju/juju/juju"
    24  	"github.com/juju/juju/network"
    25  	"github.com/juju/juju/state"
    26  	"github.com/juju/juju/version"
    27  )
    28  
    29  func init() {
    30  	common.RegisterStandardFacade("Client", 0, NewClient)
    31  }
    32  
    33  var logger = loggo.GetLogger("juju.apiserver.client")
    34  
    35  type API struct {
    36  	state     *state.State
    37  	auth      common.Authorizer
    38  	resources *common.Resources
    39  	client    *Client
    40  	// statusSetter provides common methods for updating an entity's provisioning status.
    41  	statusSetter *common.StatusSetter
    42  	toolsFinder  *common.ToolsFinder
    43  }
    44  
    45  // Client serves client-specific API methods.
    46  type Client struct {
    47  	api   *API
    48  	check *common.BlockChecker
    49  }
    50  
    51  // NewClient creates a new instance of the Client Facade.
    52  func NewClient(st *state.State, resources *common.Resources, authorizer common.Authorizer) (*Client, error) {
    53  	if !authorizer.AuthClient() {
    54  		return nil, common.ErrPerm
    55  	}
    56  	urlGetter := common.NewToolsURLGetter(st.EnvironUUID(), st)
    57  	return &Client{
    58  		api: &API{
    59  			state:        st,
    60  			auth:         authorizer,
    61  			resources:    resources,
    62  			statusSetter: common.NewStatusSetter(st, common.AuthAlways()),
    63  			toolsFinder:  common.NewToolsFinder(st, st, urlGetter),
    64  		},
    65  		check: common.NewBlockChecker(st)}, nil
    66  }
    67  
    68  func (c *Client) WatchAll() (params.AllWatcherId, error) {
    69  	w := c.api.state.Watch()
    70  	return params.AllWatcherId{
    71  		AllWatcherId: c.api.resources.Register(w),
    72  	}, nil
    73  }
    74  
    75  // ServiceSet implements the server side of Client.ServiceSet. Values set to an
    76  // empty string will be unset.
    77  //
    78  // (Deprecated) Use NewServiceSetForClientAPI instead, to preserve values set to
    79  // an empty string, and use ServiceUnset to unset values.
    80  func (c *Client) ServiceSet(p params.ServiceSet) error {
    81  	if err := c.check.ChangeAllowed(); err != nil {
    82  		return errors.Trace(err)
    83  	}
    84  	svc, err := c.api.state.Service(p.ServiceName)
    85  	if err != nil {
    86  		return err
    87  	}
    88  	return service.ServiceSetSettingsStrings(svc, p.Options)
    89  }
    90  
    91  // NewServiceSetForClientAPI implements the server side of
    92  // Client.NewServiceSetForClientAPI. This is exactly like ServiceSet except that
    93  // it does not unset values that are set to an empty string.  ServiceUnset
    94  // should be used for that.
    95  //
    96  // TODO(Nate): rename this to ServiceSet (and remove the deprecated ServiceSet)
    97  // when the GUI handles the new behavior.
    98  // TODO(mattyw, all): This api call should be move to the new service facade. The client api version will then need bumping.
    99  func (c *Client) NewServiceSetForClientAPI(p params.ServiceSet) error {
   100  	svc, err := c.api.state.Service(p.ServiceName)
   101  	if err != nil {
   102  		return err
   103  	}
   104  	return newServiceSetSettingsStringsForClientAPI(svc, p.Options)
   105  }
   106  
   107  // ServiceUnset implements the server side of Client.ServiceUnset.
   108  // TODO(mattyw, all): This api call should be move to the new service facade. The client api version will then need bumping.
   109  func (c *Client) ServiceUnset(p params.ServiceUnset) error {
   110  	if err := c.check.ChangeAllowed(); err != nil {
   111  		return errors.Trace(err)
   112  	}
   113  	svc, err := c.api.state.Service(p.ServiceName)
   114  	if err != nil {
   115  		return err
   116  	}
   117  	settings := make(charm.Settings)
   118  	for _, option := range p.Options {
   119  		settings[option] = nil
   120  	}
   121  	return svc.UpdateConfigSettings(settings)
   122  }
   123  
   124  // ServiceSetYAML implements the server side of Client.ServerSetYAML.
   125  // TODO(mattyw, all): This api call should be move to the new service facade. The client api version will then need bumping.
   126  func (c *Client) ServiceSetYAML(p params.ServiceSetYAML) error {
   127  	if err := c.check.ChangeAllowed(); err != nil {
   128  		return errors.Trace(err)
   129  	}
   130  	svc, err := c.api.state.Service(p.ServiceName)
   131  	if err != nil {
   132  		return err
   133  	}
   134  	return serviceSetSettingsYAML(svc, p.Config)
   135  }
   136  
   137  // ServiceCharmRelations implements the server side of Client.ServiceCharmRelations.
   138  // TODO(mattyw, all): This api call should be move to the new service facade. The client api version will then need bumping.
   139  func (c *Client) ServiceCharmRelations(p params.ServiceCharmRelations) (params.ServiceCharmRelationsResults, error) {
   140  	var results params.ServiceCharmRelationsResults
   141  	service, err := c.api.state.Service(p.ServiceName)
   142  	if err != nil {
   143  		return results, err
   144  	}
   145  	endpoints, err := service.Endpoints()
   146  	if err != nil {
   147  		return results, err
   148  	}
   149  	results.CharmRelations = make([]string, len(endpoints))
   150  	for i, endpoint := range endpoints {
   151  		results.CharmRelations[i] = endpoint.Relation.Name
   152  	}
   153  	return results, nil
   154  }
   155  
   156  // Resolved implements the server side of Client.Resolved.
   157  func (c *Client) Resolved(p params.Resolved) error {
   158  	if err := c.check.ChangeAllowed(); err != nil {
   159  		return errors.Trace(err)
   160  	}
   161  	unit, err := c.api.state.Unit(p.UnitName)
   162  	if err != nil {
   163  		return err
   164  	}
   165  	return unit.Resolve(p.Retry)
   166  }
   167  
   168  // PublicAddress implements the server side of Client.PublicAddress.
   169  func (c *Client) PublicAddress(p params.PublicAddress) (results params.PublicAddressResults, err error) {
   170  	switch {
   171  	case names.IsValidMachine(p.Target):
   172  		machine, err := c.api.state.Machine(p.Target)
   173  		if err != nil {
   174  			return results, err
   175  		}
   176  		addr := network.SelectPublicAddress(machine.Addresses())
   177  		if addr == "" {
   178  			return results, fmt.Errorf("machine %q has no public address", machine)
   179  		}
   180  		return params.PublicAddressResults{PublicAddress: addr}, nil
   181  
   182  	case names.IsValidUnit(p.Target):
   183  		unit, err := c.api.state.Unit(p.Target)
   184  		if err != nil {
   185  			return results, err
   186  		}
   187  		addr, ok := unit.PublicAddress()
   188  		if !ok {
   189  			return results, fmt.Errorf("unit %q has no public address", unit)
   190  		}
   191  		return params.PublicAddressResults{PublicAddress: addr}, nil
   192  	}
   193  	return results, fmt.Errorf("unknown unit or machine %q", p.Target)
   194  }
   195  
   196  // PrivateAddress implements the server side of Client.PrivateAddress.
   197  func (c *Client) PrivateAddress(p params.PrivateAddress) (results params.PrivateAddressResults, err error) {
   198  	switch {
   199  	case names.IsValidMachine(p.Target):
   200  		machine, err := c.api.state.Machine(p.Target)
   201  		if err != nil {
   202  			return results, err
   203  		}
   204  		addr := network.SelectInternalAddress(machine.Addresses(), false)
   205  		if addr == "" {
   206  			return results, fmt.Errorf("machine %q has no internal address", machine)
   207  		}
   208  		return params.PrivateAddressResults{PrivateAddress: addr}, nil
   209  
   210  	case names.IsValidUnit(p.Target):
   211  		unit, err := c.api.state.Unit(p.Target)
   212  		if err != nil {
   213  			return results, err
   214  		}
   215  		addr, ok := unit.PrivateAddress()
   216  		if !ok {
   217  			return results, fmt.Errorf("unit %q has no internal address", unit)
   218  		}
   219  		return params.PrivateAddressResults{PrivateAddress: addr}, nil
   220  	}
   221  	return results, fmt.Errorf("unknown unit or machine %q", p.Target)
   222  }
   223  
   224  // ServiceExpose changes the juju-managed firewall to expose any ports that
   225  // were also explicitly marked by units as open.
   226  // TODO(mattyw, all): This api call should be move to the new service facade. The client api version will then need bumping.
   227  func (c *Client) ServiceExpose(args params.ServiceExpose) error {
   228  	if err := c.check.ChangeAllowed(); err != nil {
   229  		return errors.Trace(err)
   230  	}
   231  	svc, err := c.api.state.Service(args.ServiceName)
   232  	if err != nil {
   233  		return err
   234  	}
   235  	return svc.SetExposed()
   236  }
   237  
   238  // ServiceUnexpose changes the juju-managed firewall to unexpose any ports that
   239  // were also explicitly marked by units as open.
   240  // TODO(mattyw, all): This api call should be move to the new service facade. The client api version will then need bumping.
   241  func (c *Client) ServiceUnexpose(args params.ServiceUnexpose) error {
   242  	if err := c.check.ChangeAllowed(); err != nil {
   243  		return errors.Trace(err)
   244  	}
   245  	svc, err := c.api.state.Service(args.ServiceName)
   246  	if err != nil {
   247  		return err
   248  	}
   249  	return svc.ClearExposed()
   250  }
   251  
   252  // ServiceDeploy fetches the charm from the charm store and deploys it.
   253  // AddCharm or AddLocalCharm should be called to add the charm
   254  // before calling ServiceDeploy, although for backward compatibility
   255  // this is not necessary until 1.16 support is removed.
   256  func (c *Client) ServiceDeploy(args params.ServiceDeploy) error {
   257  	if err := c.check.ChangeAllowed(); err != nil {
   258  		return errors.Trace(err)
   259  	}
   260  	return service.DeployService(c.api.state, c.api.auth.GetAuthTag().String(), args)
   261  }
   262  
   263  // ServiceDeployWithNetworks works exactly like ServiceDeploy, but
   264  // allows specifying networks to include or exclude on the machine
   265  // where the charm gets deployed (either with args.Network or with
   266  // constraints).
   267  func (c *Client) ServiceDeployWithNetworks(args params.ServiceDeploy) error {
   268  	return c.ServiceDeploy(args)
   269  }
   270  
   271  // ServiceUpdate updates the service attributes, including charm URL,
   272  // minimum number of units, settings and constraints.
   273  // All parameters in params.ServiceUpdate except the service name are optional.
   274  func (c *Client) ServiceUpdate(args params.ServiceUpdate) error {
   275  	if !args.ForceCharmUrl {
   276  		if err := c.check.ChangeAllowed(); err != nil {
   277  			return errors.Trace(err)
   278  		}
   279  	}
   280  	svc, err := c.api.state.Service(args.ServiceName)
   281  	if err != nil {
   282  		return err
   283  	}
   284  	// Set the charm for the given service.
   285  	if args.CharmUrl != "" {
   286  		if err = c.serviceSetCharm(svc, args.CharmUrl, args.ForceCharmUrl); err != nil {
   287  			return err
   288  		}
   289  	}
   290  	// Set the minimum number of units for the given service.
   291  	if args.MinUnits != nil {
   292  		if err = svc.SetMinUnits(*args.MinUnits); err != nil {
   293  			return err
   294  		}
   295  	}
   296  	// Set up service's settings.
   297  	if args.SettingsYAML != "" {
   298  		if err = serviceSetSettingsYAML(svc, args.SettingsYAML); err != nil {
   299  			return err
   300  		}
   301  	} else if len(args.SettingsStrings) > 0 {
   302  		if err = service.ServiceSetSettingsStrings(svc, args.SettingsStrings); err != nil {
   303  			return err
   304  		}
   305  	}
   306  	// Update service's constraints.
   307  	if args.Constraints != nil {
   308  		return svc.SetConstraints(*args.Constraints)
   309  	}
   310  	return nil
   311  }
   312  
   313  // serviceSetCharm sets the charm for the given service.
   314  func (c *Client) serviceSetCharm(service *state.Service, url string, force bool) error {
   315  	curl, err := charm.ParseURL(url)
   316  	if err != nil {
   317  		return err
   318  	}
   319  	sch, err := c.api.state.Charm(curl)
   320  	if errors.IsNotFound(err) {
   321  		// Charms should be added before trying to use them, with
   322  		// AddCharm or AddLocalCharm API calls. When they're not,
   323  		// we're reverting to 1.16 compatibility mode.
   324  		return c.serviceSetCharm1dot16(service, curl, force)
   325  	}
   326  	if err != nil {
   327  		return err
   328  	}
   329  	return service.SetCharm(sch, force)
   330  }
   331  
   332  // serviceSetCharm1dot16 sets the charm for the given service in 1.16
   333  // compatibility mode. Remove this when support for 1.16 is dropped.
   334  func (c *Client) serviceSetCharm1dot16(service *state.Service, curl *charm.URL, force bool) error {
   335  	if curl.Schema != "cs" {
   336  		return fmt.Errorf(`charm url has unsupported schema %q`, curl.Schema)
   337  	}
   338  	if curl.Revision < 0 {
   339  		return fmt.Errorf("charm url must include revision")
   340  	}
   341  	err := c.AddCharm(params.CharmURL{
   342  		URL: curl.String(),
   343  	})
   344  	if err != nil {
   345  		return err
   346  	}
   347  	ch, err := c.api.state.Charm(curl)
   348  	if err != nil {
   349  		return err
   350  	}
   351  	return service.SetCharm(ch, force)
   352  }
   353  
   354  // serviceSetSettingsYAML updates the settings for the given service,
   355  // taking the configuration from a YAML string.
   356  func serviceSetSettingsYAML(service *state.Service, settings string) error {
   357  	ch, _, err := service.Charm()
   358  	if err != nil {
   359  		return err
   360  	}
   361  	changes, err := ch.Config().ParseSettingsYAML([]byte(settings), service.Name())
   362  	if err != nil {
   363  		return err
   364  	}
   365  	return service.UpdateConfigSettings(changes)
   366  }
   367  
   368  // newServiceSetSettingsStringsForClientAPI updates the settings for the given
   369  // service, taking the configuration from a map of strings.
   370  //
   371  // TODO(Nate): replace serviceSetSettingsStrings with this onces the GUI no
   372  // longer expects to be able to unset values by sending an empty string.
   373  func newServiceSetSettingsStringsForClientAPI(service *state.Service, settings map[string]string) error {
   374  	ch, _, err := service.Charm()
   375  	if err != nil {
   376  		return err
   377  	}
   378  
   379  	// Validate the settings.
   380  	changes, err := ch.Config().ParseSettingsStrings(settings)
   381  	if err != nil {
   382  		return err
   383  	}
   384  
   385  	return service.UpdateConfigSettings(changes)
   386  }
   387  
   388  // ServiceSetCharm sets the charm for a given service.
   389  // TODO(mattyw, all): This api call should be move to the new service facade. The client api version will then need bumping.
   390  func (c *Client) ServiceSetCharm(args params.ServiceSetCharm) error {
   391  	// when forced, don't block
   392  	if !args.Force {
   393  		if err := c.check.ChangeAllowed(); err != nil {
   394  			return errors.Trace(err)
   395  		}
   396  	}
   397  	service, err := c.api.state.Service(args.ServiceName)
   398  	if err != nil {
   399  		return err
   400  	}
   401  	return c.serviceSetCharm(service, args.CharmUrl, args.Force)
   402  }
   403  
   404  // addServiceUnits adds a given number of units to a service.
   405  func addServiceUnits(state *state.State, args params.AddServiceUnits) ([]*state.Unit, error) {
   406  	service, err := state.Service(args.ServiceName)
   407  	if err != nil {
   408  		return nil, err
   409  	}
   410  	if args.NumUnits < 1 {
   411  		return nil, fmt.Errorf("must add at least one unit")
   412  	}
   413  	if args.NumUnits > 1 && args.ToMachineSpec != "" {
   414  		return nil, fmt.Errorf("cannot use NumUnits with ToMachineSpec")
   415  	}
   416  
   417  	if args.ToMachineSpec != "" && names.IsValidMachine(args.ToMachineSpec) {
   418  		_, err = state.Machine(args.ToMachineSpec)
   419  		if err != nil {
   420  			return nil, errors.Annotatef(err, `cannot add units for service "%v" to machine %v`, args.ServiceName, args.ToMachineSpec)
   421  		}
   422  	}
   423  	return jjj.AddUnits(state, service, args.NumUnits, args.ToMachineSpec)
   424  }
   425  
   426  // AddServiceUnits adds a given number of units to a service.
   427  func (c *Client) AddServiceUnits(args params.AddServiceUnits) (params.AddServiceUnitsResults, error) {
   428  	if err := c.check.ChangeAllowed(); err != nil {
   429  		return params.AddServiceUnitsResults{}, errors.Trace(err)
   430  	}
   431  	units, err := addServiceUnits(c.api.state, args)
   432  	if err != nil {
   433  		return params.AddServiceUnitsResults{}, err
   434  	}
   435  	unitNames := make([]string, len(units))
   436  	for i, unit := range units {
   437  		unitNames[i] = unit.String()
   438  	}
   439  	return params.AddServiceUnitsResults{Units: unitNames}, nil
   440  }
   441  
   442  // DestroyServiceUnits removes a given set of service units.
   443  func (c *Client) DestroyServiceUnits(args params.DestroyServiceUnits) error {
   444  	if err := c.check.RemoveAllowed(); err != nil {
   445  		return errors.Trace(err)
   446  	}
   447  	var errs []string
   448  	for _, name := range args.UnitNames {
   449  		unit, err := c.api.state.Unit(name)
   450  		switch {
   451  		case errors.IsNotFound(err):
   452  			err = fmt.Errorf("unit %q does not exist", name)
   453  		case err != nil:
   454  		case unit.Life() != state.Alive:
   455  			continue
   456  		case unit.IsPrincipal():
   457  			err = unit.Destroy()
   458  		default:
   459  			err = fmt.Errorf("unit %q is a subordinate", name)
   460  		}
   461  		if err != nil {
   462  			errs = append(errs, err.Error())
   463  		}
   464  	}
   465  	return destroyErr("units", args.UnitNames, errs)
   466  }
   467  
   468  // ServiceDestroy destroys a given service.
   469  // TODO(mattyw, all): This api call should be move to the new service facade. The client api version will then need bumping.
   470  func (c *Client) ServiceDestroy(args params.ServiceDestroy) error {
   471  	if err := c.check.RemoveAllowed(); err != nil {
   472  		return errors.Trace(err)
   473  	}
   474  	svc, err := c.api.state.Service(args.ServiceName)
   475  	if err != nil {
   476  		return err
   477  	}
   478  	return svc.Destroy()
   479  }
   480  
   481  // GetServiceConstraints returns the constraints for a given service.
   482  // TODO(mattyw, all): This api call should be move to the new service facade. The client api version will then need bumping.
   483  func (c *Client) GetServiceConstraints(args params.GetServiceConstraints) (params.GetConstraintsResults, error) {
   484  	svc, err := c.api.state.Service(args.ServiceName)
   485  	if err != nil {
   486  		return params.GetConstraintsResults{}, err
   487  	}
   488  	cons, err := svc.Constraints()
   489  	return params.GetConstraintsResults{cons}, err
   490  }
   491  
   492  // GetEnvironmentConstraints returns the constraints for the environment.
   493  func (c *Client) GetEnvironmentConstraints() (params.GetConstraintsResults, error) {
   494  	cons, err := c.api.state.EnvironConstraints()
   495  	if err != nil {
   496  		return params.GetConstraintsResults{}, err
   497  	}
   498  	return params.GetConstraintsResults{cons}, nil
   499  }
   500  
   501  // SetServiceConstraints sets the constraints for a given service.
   502  // TODO(mattyw, all): This api call should be move to the new service facade. The client api version will then need bumping.
   503  func (c *Client) SetServiceConstraints(args params.SetConstraints) error {
   504  	if err := c.check.ChangeAllowed(); err != nil {
   505  		return errors.Trace(err)
   506  	}
   507  	svc, err := c.api.state.Service(args.ServiceName)
   508  	if err != nil {
   509  		return err
   510  	}
   511  	return svc.SetConstraints(args.Constraints)
   512  }
   513  
   514  // SetEnvironmentConstraints sets the constraints for the environment.
   515  func (c *Client) SetEnvironmentConstraints(args params.SetConstraints) error {
   516  	if err := c.check.ChangeAllowed(); err != nil {
   517  		return errors.Trace(err)
   518  	}
   519  	return c.api.state.SetEnvironConstraints(args.Constraints)
   520  }
   521  
   522  // AddRelation adds a relation between the specified endpoints and returns the relation info.
   523  func (c *Client) AddRelation(args params.AddRelation) (params.AddRelationResults, error) {
   524  	if err := c.check.ChangeAllowed(); err != nil {
   525  		return params.AddRelationResults{}, errors.Trace(err)
   526  	}
   527  	inEps, err := c.api.state.InferEndpoints(args.Endpoints...)
   528  	if err != nil {
   529  		return params.AddRelationResults{}, err
   530  	}
   531  	rel, err := c.api.state.AddRelation(inEps...)
   532  	if err != nil {
   533  		return params.AddRelationResults{}, err
   534  	}
   535  	outEps := make(map[string]charm.Relation)
   536  	for _, inEp := range inEps {
   537  		outEp, err := rel.Endpoint(inEp.ServiceName)
   538  		if err != nil {
   539  			return params.AddRelationResults{}, err
   540  		}
   541  		outEps[inEp.ServiceName] = outEp.Relation
   542  	}
   543  	return params.AddRelationResults{Endpoints: outEps}, nil
   544  }
   545  
   546  // DestroyRelation removes the relation between the specified endpoints.
   547  func (c *Client) DestroyRelation(args params.DestroyRelation) error {
   548  	if err := c.check.RemoveAllowed(); err != nil {
   549  		return errors.Trace(err)
   550  	}
   551  	eps, err := c.api.state.InferEndpoints(args.Endpoints...)
   552  	if err != nil {
   553  		return err
   554  	}
   555  	rel, err := c.api.state.EndpointsRelation(eps...)
   556  	if err != nil {
   557  		return err
   558  	}
   559  	return rel.Destroy()
   560  }
   561  
   562  // AddMachines adds new machines with the supplied parameters.
   563  func (c *Client) AddMachines(args params.AddMachines) (params.AddMachinesResults, error) {
   564  	return c.AddMachinesV2(args)
   565  }
   566  
   567  // AddMachinesV2 adds new machines with the supplied parameters.
   568  func (c *Client) AddMachinesV2(args params.AddMachines) (params.AddMachinesResults, error) {
   569  	results := params.AddMachinesResults{
   570  		Machines: make([]params.AddMachinesResult, len(args.MachineParams)),
   571  	}
   572  	if err := c.check.ChangeAllowed(); err != nil {
   573  		return results, errors.Trace(err)
   574  	}
   575  	for i, p := range args.MachineParams {
   576  		m, err := c.addOneMachine(p)
   577  		results.Machines[i].Error = common.ServerError(err)
   578  		if err == nil {
   579  			results.Machines[i].Machine = m.Id()
   580  		}
   581  	}
   582  	return results, nil
   583  }
   584  
   585  // InjectMachines injects a machine into state with provisioned status.
   586  func (c *Client) InjectMachines(args params.AddMachines) (params.AddMachinesResults, error) {
   587  	return c.AddMachines(args)
   588  }
   589  
   590  func (c *Client) addOneMachine(p params.AddMachineParams) (*state.Machine, error) {
   591  	if p.ParentId != "" && p.ContainerType == "" {
   592  		return nil, fmt.Errorf("parent machine specified without container type")
   593  	}
   594  	if p.ContainerType != "" && p.Placement != nil {
   595  		return nil, fmt.Errorf("container type and placement are mutually exclusive")
   596  	}
   597  	if p.Placement != nil {
   598  		// Extract container type and parent from container placement directives.
   599  		containerType, err := instance.ParseContainerType(p.Placement.Scope)
   600  		if err == nil {
   601  			p.ContainerType = containerType
   602  			p.ParentId = p.Placement.Directive
   603  			p.Placement = nil
   604  		}
   605  	}
   606  
   607  	if p.ContainerType != "" || p.Placement != nil {
   608  		// Guard against dubious client by making sure that
   609  		// the following attributes can only be set when we're
   610  		// not using placement.
   611  		p.InstanceId = ""
   612  		p.Nonce = ""
   613  		p.HardwareCharacteristics = instance.HardwareCharacteristics{}
   614  		p.Addrs = nil
   615  	}
   616  
   617  	if p.Series == "" {
   618  		conf, err := c.api.state.EnvironConfig()
   619  		if err != nil {
   620  			return nil, err
   621  		}
   622  		p.Series = config.PreferredSeries(conf)
   623  	}
   624  
   625  	var placementDirective string
   626  	if p.Placement != nil {
   627  		env, err := c.api.state.Environment()
   628  		if err != nil {
   629  			return nil, err
   630  		}
   631  		// For 1.21 we should support both UUID and name, and with 1.22
   632  		// just support UUID
   633  		if p.Placement.Scope != env.Name() && p.Placement.Scope != env.UUID() {
   634  			return nil, fmt.Errorf("invalid environment name %q", p.Placement.Scope)
   635  		}
   636  		placementDirective = p.Placement.Directive
   637  	}
   638  
   639  	jobs, err := common.StateJobs(p.Jobs)
   640  	if err != nil {
   641  		return nil, err
   642  	}
   643  	template := state.MachineTemplate{
   644  		Series:      p.Series,
   645  		Constraints: p.Constraints,
   646  		InstanceId:  p.InstanceId,
   647  		Jobs:        jobs,
   648  		Nonce:       p.Nonce,
   649  		HardwareCharacteristics: p.HardwareCharacteristics,
   650  		Addresses:               params.NetworkAddresses(p.Addrs),
   651  		Placement:               placementDirective,
   652  	}
   653  	if p.ContainerType == "" {
   654  		return c.api.state.AddOneMachine(template)
   655  	}
   656  	if p.ParentId != "" {
   657  		return c.api.state.AddMachineInsideMachine(template, p.ParentId, p.ContainerType)
   658  	}
   659  	return c.api.state.AddMachineInsideNewMachine(template, template, p.ContainerType)
   660  }
   661  
   662  // ProvisioningScript returns a shell script that, when run,
   663  // provisions a machine agent on the machine executing the script.
   664  func (c *Client) ProvisioningScript(args params.ProvisioningScriptParams) (params.ProvisioningScriptResult, error) {
   665  	var result params.ProvisioningScriptResult
   666  	icfg, err := InstanceConfig(c.api.state, args.MachineId, args.Nonce, args.DataDir)
   667  	if err != nil {
   668  		return result, err
   669  	}
   670  
   671  	// Until DisablePackageCommands is retired, for backwards
   672  	// compatibility, we must respect the client's request and
   673  	// override any environment settings the user may have specified.
   674  	// If the client does specify this setting, it will only ever be
   675  	// true. False indicates the client doesn't care and we should use
   676  	// what's specified in the environments.yaml file.
   677  	if args.DisablePackageCommands {
   678  		icfg.EnableOSRefreshUpdate = false
   679  		icfg.EnableOSUpgrade = false
   680  	} else if cfg, err := c.api.state.EnvironConfig(); err != nil {
   681  		return result, err
   682  	} else {
   683  		icfg.EnableOSUpgrade = cfg.EnableOSUpgrade()
   684  		icfg.EnableOSRefreshUpdate = cfg.EnableOSRefreshUpdate()
   685  	}
   686  
   687  	result.Script, err = manual.ProvisioningScript(icfg)
   688  	return result, err
   689  }
   690  
   691  // DestroyMachines removes a given set of machines.
   692  func (c *Client) DestroyMachines(args params.DestroyMachines) error {
   693  	var errs []string
   694  	for _, id := range args.MachineNames {
   695  		machine, err := c.api.state.Machine(id)
   696  		switch {
   697  		case errors.IsNotFound(err):
   698  			err = fmt.Errorf("machine %s does not exist", id)
   699  		case err != nil:
   700  		case args.Force:
   701  			err = machine.ForceDestroy()
   702  		case machine.Life() != state.Alive:
   703  			continue
   704  		default:
   705  			{
   706  				if err := c.check.RemoveAllowed(); err != nil {
   707  					return errors.Trace(err)
   708  				}
   709  				err = machine.Destroy()
   710  			}
   711  		}
   712  		if err != nil {
   713  			errs = append(errs, err.Error())
   714  		}
   715  	}
   716  	return destroyErr("machines", args.MachineNames, errs)
   717  }
   718  
   719  // CharmInfo returns information about the requested charm.
   720  func (c *Client) CharmInfo(args params.CharmInfo) (api.CharmInfo, error) {
   721  	curl, err := charm.ParseURL(args.CharmURL)
   722  	if err != nil {
   723  		return api.CharmInfo{}, err
   724  	}
   725  	charm, err := c.api.state.Charm(curl)
   726  	if err != nil {
   727  		return api.CharmInfo{}, err
   728  	}
   729  	info := api.CharmInfo{
   730  		Revision: charm.Revision(),
   731  		URL:      curl.String(),
   732  		Config:   charm.Config(),
   733  		Meta:     charm.Meta(),
   734  		Actions:  charm.Actions(),
   735  	}
   736  	return info, nil
   737  }
   738  
   739  // EnvironmentInfo returns information about the current environment (default
   740  // series and type).
   741  func (c *Client) EnvironmentInfo() (api.EnvironmentInfo, error) {
   742  	state := c.api.state
   743  	conf, err := state.EnvironConfig()
   744  	if err != nil {
   745  		return api.EnvironmentInfo{}, err
   746  	}
   747  	env, err := state.Environment()
   748  	if err != nil {
   749  		return api.EnvironmentInfo{}, err
   750  	}
   751  
   752  	info := api.EnvironmentInfo{
   753  		DefaultSeries: config.PreferredSeries(conf),
   754  		ProviderType:  conf.Type(),
   755  		Name:          conf.Name(),
   756  		UUID:          env.UUID(),
   757  		ServerUUID:    env.ServerUUID(),
   758  	}
   759  	return info, nil
   760  }
   761  
   762  // ShareEnvironment manages allowing and denying the given user(s) access to the environment.
   763  func (c *Client) ShareEnvironment(args params.ModifyEnvironUsers) (result params.ErrorResults, err error) {
   764  	var createdBy names.UserTag
   765  	var ok bool
   766  	if createdBy, ok = c.api.auth.GetAuthTag().(names.UserTag); !ok {
   767  		return result, errors.Errorf("api connection is not through a user")
   768  	}
   769  
   770  	result = params.ErrorResults{
   771  		Results: make([]params.ErrorResult, len(args.Changes)),
   772  	}
   773  	if len(args.Changes) == 0 {
   774  		return result, nil
   775  	}
   776  
   777  	for i, arg := range args.Changes {
   778  		userTagString := arg.UserTag
   779  		user, err := names.ParseUserTag(userTagString)
   780  		if err != nil {
   781  			result.Results[i].Error = common.ServerError(errors.Annotate(err, "could not share environment"))
   782  			continue
   783  		}
   784  		switch arg.Action {
   785  		case params.AddEnvUser:
   786  			_, err := c.api.state.AddEnvironmentUser(user, createdBy, "")
   787  			if err != nil {
   788  				err = errors.Annotate(err, "could not share environment")
   789  				result.Results[i].Error = common.ServerError(err)
   790  			}
   791  		case params.RemoveEnvUser:
   792  			err := c.api.state.RemoveEnvironmentUser(user)
   793  			if err != nil {
   794  				err = errors.Annotate(err, "could not unshare environment")
   795  				result.Results[i].Error = common.ServerError(err)
   796  			}
   797  		default:
   798  			result.Results[i].Error = common.ServerError(errors.Errorf("unknown action %q", arg.Action))
   799  		}
   800  	}
   801  	return result, nil
   802  }
   803  
   804  // EnvUserInfo returns information on all users in the environment.
   805  func (c *Client) EnvUserInfo() (params.EnvUserInfoResults, error) {
   806  	var results params.EnvUserInfoResults
   807  	env, err := c.api.state.Environment()
   808  	if err != nil {
   809  		return results, errors.Trace(err)
   810  	}
   811  	users, err := env.Users()
   812  	if err != nil {
   813  		return results, errors.Trace(err)
   814  	}
   815  
   816  	for _, user := range users {
   817  		results.Results = append(results.Results, params.EnvUserInfoResult{
   818  			Result: &params.EnvUserInfo{
   819  				UserName:       user.UserName(),
   820  				DisplayName:    user.DisplayName(),
   821  				CreatedBy:      user.CreatedBy(),
   822  				DateCreated:    user.DateCreated(),
   823  				LastConnection: user.LastConnection(),
   824  			},
   825  		})
   826  	}
   827  	return results, nil
   828  }
   829  
   830  // GetAnnotations returns annotations about a given entity.
   831  // This API is now deprecated - "Annotations" client should be used instead.
   832  // TODO(anastasiamac) remove for Juju 2.x
   833  func (c *Client) GetAnnotations(args params.GetAnnotations) (params.GetAnnotationsResults, error) {
   834  	nothing := params.GetAnnotationsResults{}
   835  	tag, err := c.parseEntityTag(args.Tag)
   836  	if err != nil {
   837  		return nothing, errors.Trace(err)
   838  	}
   839  	entity, err := c.findEntity(tag)
   840  	if err != nil {
   841  		return nothing, errors.Trace(err)
   842  	}
   843  	ann, err := c.api.state.Annotations(entity)
   844  	if err != nil {
   845  		return nothing, errors.Trace(err)
   846  	}
   847  	return params.GetAnnotationsResults{Annotations: ann}, nil
   848  }
   849  
   850  func (c *Client) parseEntityTag(tag0 string) (names.Tag, error) {
   851  	tag, err := names.ParseTag(tag0)
   852  	if err != nil {
   853  		return nil, errors.Trace(err)
   854  	}
   855  	if tag.Kind() == names.CharmTagKind {
   856  		return nil, common.NotSupportedError(tag, "client.annotations")
   857  	}
   858  	return tag, nil
   859  }
   860  
   861  func (c *Client) findEntity(tag names.Tag) (state.GlobalEntity, error) {
   862  	entity0, err := c.api.state.FindEntity(tag)
   863  	if err != nil {
   864  		return nil, err
   865  	}
   866  	entity, ok := entity0.(state.GlobalEntity)
   867  	if !ok {
   868  		return nil, common.NotSupportedError(tag, "annotations")
   869  	}
   870  	return entity, nil
   871  }
   872  
   873  // SetAnnotations stores annotations about a given entity.
   874  // This API is now deprecated - "Annotations" client should be used instead.
   875  // TODO(anastasiamac) remove for Juju 2.x
   876  func (c *Client) SetAnnotations(args params.SetAnnotations) error {
   877  	tag, err := c.parseEntityTag(args.Tag)
   878  	if err != nil {
   879  		return errors.Trace(err)
   880  	}
   881  	entity, err := c.findEntity(tag)
   882  	if err != nil {
   883  		return errors.Trace(err)
   884  	}
   885  	return c.api.state.SetAnnotations(entity, args.Pairs)
   886  }
   887  
   888  // AgentVersion returns the current version that the API server is running.
   889  func (c *Client) AgentVersion() (params.AgentVersionResult, error) {
   890  	return params.AgentVersionResult{Version: version.Current.Number}, nil
   891  }
   892  
   893  // EnvironmentGet implements the server-side part of the
   894  // get-environment CLI command.
   895  func (c *Client) EnvironmentGet() (params.EnvironmentConfigResults, error) {
   896  	result := params.EnvironmentConfigResults{}
   897  	// Get the existing environment config from the state.
   898  	config, err := c.api.state.EnvironConfig()
   899  	if err != nil {
   900  		return result, err
   901  	}
   902  	result.Config = config.AllAttrs()
   903  	return result, nil
   904  }
   905  
   906  // EnvironmentSet implements the server-side part of the
   907  // set-environment CLI command.
   908  func (c *Client) EnvironmentSet(args params.EnvironmentSet) error {
   909  	if err := c.check.ChangeAllowed(); err != nil {
   910  		return errors.Trace(err)
   911  	}
   912  	// Make sure we don't allow changing agent-version.
   913  	checkAgentVersion := func(updateAttrs map[string]interface{}, removeAttrs []string, oldConfig *config.Config) error {
   914  		if v, found := updateAttrs["agent-version"]; found {
   915  			oldVersion, _ := oldConfig.AgentVersion()
   916  			if v != oldVersion.String() {
   917  				return fmt.Errorf("agent-version cannot be changed")
   918  			}
   919  		}
   920  		return nil
   921  	}
   922  	// Replace any deprecated attributes with their new values.
   923  	attrs := config.ProcessDeprecatedAttributes(args.Config)
   924  	// TODO(waigani) 2014-3-11 #1167616
   925  	// Add a txn retry loop to ensure that the settings on disk have not
   926  	// changed underneath us.
   927  	return c.api.state.UpdateEnvironConfig(attrs, nil, checkAgentVersion)
   928  }
   929  
   930  // EnvironmentUnset implements the server-side part of the
   931  // set-environment CLI command.
   932  func (c *Client) EnvironmentUnset(args params.EnvironmentUnset) error {
   933  	if err := c.check.ChangeAllowed(); err != nil {
   934  		return errors.Trace(err)
   935  	}
   936  	// TODO(waigani) 2014-3-11 #1167616
   937  	// Add a txn retry loop to ensure that the settings on disk have not
   938  	// changed underneath us.
   939  	return c.api.state.UpdateEnvironConfig(nil, args.Keys, nil)
   940  }
   941  
   942  // SetEnvironAgentVersion sets the environment agent version.
   943  func (c *Client) SetEnvironAgentVersion(args params.SetEnvironAgentVersion) error {
   944  	if err := c.check.ChangeAllowed(); err != nil {
   945  		return errors.Trace(err)
   946  	}
   947  	return c.api.state.SetEnvironAgentVersion(args.Version)
   948  }
   949  
   950  // AbortCurrentUpgrade aborts and archives the current upgrade
   951  // synchronisation record, if any.
   952  func (c *Client) AbortCurrentUpgrade() error {
   953  	if err := c.check.ChangeAllowed(); err != nil {
   954  		return errors.Trace(err)
   955  	}
   956  	return c.api.state.AbortCurrentUpgrade()
   957  }
   958  
   959  // FindTools returns a List containing all tools matching the given parameters.
   960  func (c *Client) FindTools(args params.FindToolsParams) (params.FindToolsResult, error) {
   961  	return c.api.toolsFinder.FindTools(args)
   962  }
   963  
   964  func destroyErr(desc string, ids, errs []string) error {
   965  	if len(errs) == 0 {
   966  		return nil
   967  	}
   968  	msg := "some %s were not destroyed"
   969  	if len(errs) == len(ids) {
   970  		msg = "no %s were destroyed"
   971  	}
   972  	msg = fmt.Sprintf(msg, desc)
   973  	return fmt.Errorf("%s: %s", msg, strings.Join(errs, "; "))
   974  }
   975  
   976  func (c *Client) AddCharm(args params.CharmURL) error {
   977  	return service.AddCharmWithAuthorization(c.api.state, params.AddCharmWithAuthorization{
   978  		URL: args.URL,
   979  	})
   980  }
   981  
   982  // AddCharmWithAuthorization adds the given charm URL (which must include revision) to
   983  // the environment, if it does not exist yet. Local charms are not
   984  // supported, only charm store URLs. See also AddLocalCharm().
   985  //
   986  // The authorization macaroon, args.CharmStoreMacaroon, may be
   987  // omitted, in which case this call is equivalent to AddCharm.
   988  func (c *Client) AddCharmWithAuthorization(args params.AddCharmWithAuthorization) error {
   989  	return service.AddCharmWithAuthorization(c.api.state, args)
   990  }
   991  
   992  // ResolveCharm resolves the best available charm URLs with series, for charm
   993  // locations without a series specified.
   994  func (c *Client) ResolveCharms(args params.ResolveCharms) (params.ResolveCharmResults, error) {
   995  	return service.ResolveCharms(c.api.state, args)
   996  }
   997  
   998  // RetryProvisioning marks a provisioning error as transient on the machines.
   999  func (c *Client) RetryProvisioning(p params.Entities) (params.ErrorResults, error) {
  1000  	if err := c.check.ChangeAllowed(); err != nil {
  1001  		return params.ErrorResults{}, errors.Trace(err)
  1002  	}
  1003  	entityStatus := make([]params.EntityStatus, len(p.Entities))
  1004  	for i, entity := range p.Entities {
  1005  		entityStatus[i] = params.EntityStatus{Tag: entity.Tag, Data: map[string]interface{}{"transient": true}}
  1006  	}
  1007  	return c.api.statusSetter.UpdateStatus(params.SetStatus{
  1008  		Entities: entityStatus,
  1009  	})
  1010  }
  1011  
  1012  // APIHostPorts returns the API host/port addresses stored in state.
  1013  func (c *Client) APIHostPorts() (result params.APIHostPortsResult, err error) {
  1014  	var servers [][]network.HostPort
  1015  	if servers, err = c.api.state.APIHostPorts(); err != nil {
  1016  		return params.APIHostPortsResult{}, err
  1017  	}
  1018  	result.Servers = params.FromNetworkHostsPorts(servers)
  1019  	return result, nil
  1020  }
  1021  
  1022  // EnsureAvailability ensures the availability of Juju state servers.
  1023  // DEPRECATED: remove when we stop supporting 1.20 and earlier clients.
  1024  // This API is now on the HighAvailability facade.
  1025  func (c *Client) EnsureAvailability(args params.StateServersSpecs) (params.StateServersChangeResults, error) {
  1026  	if err := c.check.ChangeAllowed(); err != nil {
  1027  		return params.StateServersChangeResults{}, errors.Trace(err)
  1028  	}
  1029  	results := params.StateServersChangeResults{Results: make([]params.StateServersChangeResult, len(args.Specs))}
  1030  	for i, stateServersSpec := range args.Specs {
  1031  		result, err := highavailability.EnsureAvailabilitySingle(c.api.state, stateServersSpec)
  1032  		results.Results[i].Result = result
  1033  		results.Results[i].Error = common.ServerError(err)
  1034  	}
  1035  	return results, nil
  1036  }