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: ¶ms.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 }