OLD | NEW |
1 // Copyright 2012, 2013 Canonical Ltd. | 1 // Copyright 2012, 2013 Canonical Ltd. |
2 // Licensed under the AGPLv3, see LICENCE file for details. | 2 // Licensed under the AGPLv3, see LICENCE file for details. |
3 | 3 |
4 // Stub provider for OpenStack, using goose will be implemented here | 4 // Stub provider for OpenStack, using goose will be implemented here |
5 | 5 |
6 package openstack | 6 package openstack |
7 | 7 |
8 import ( | 8 import ( |
9 "encoding/json" | 9 "encoding/json" |
10 "errors" | 10 "errors" |
11 "fmt" | 11 "fmt" |
12 "io/ioutil" | 12 "io/ioutil" |
13 "launchpad.net/goose/client" | 13 "launchpad.net/goose/client" |
14 gooseerrors "launchpad.net/goose/errors" | 14 gooseerrors "launchpad.net/goose/errors" |
15 "launchpad.net/goose/identity" | 15 "launchpad.net/goose/identity" |
16 "launchpad.net/goose/nova" | 16 "launchpad.net/goose/nova" |
17 "launchpad.net/goose/swift" | 17 "launchpad.net/goose/swift" |
18 "launchpad.net/juju-core/constraints" | 18 "launchpad.net/juju-core/constraints" |
19 "launchpad.net/juju-core/environs" | 19 "launchpad.net/juju-core/environs" |
20 "launchpad.net/juju-core/environs/cloudinit" | 20 "launchpad.net/juju-core/environs/cloudinit" |
21 "launchpad.net/juju-core/environs/config" | 21 "launchpad.net/juju-core/environs/config" |
22 "launchpad.net/juju-core/environs/imagemetadata" | 22 "launchpad.net/juju-core/environs/imagemetadata" |
23 "launchpad.net/juju-core/environs/instances" | 23 "launchpad.net/juju-core/environs/instances" |
24 "launchpad.net/juju-core/environs/tools" | 24 "launchpad.net/juju-core/environs/tools" |
25 coreerrors "launchpad.net/juju-core/errors" | 25 coreerrors "launchpad.net/juju-core/errors" |
| 26 "launchpad.net/juju-core/instance" |
26 "launchpad.net/juju-core/log" | 27 "launchpad.net/juju-core/log" |
27 "launchpad.net/juju-core/state" | 28 "launchpad.net/juju-core/state" |
28 "launchpad.net/juju-core/state/api" | 29 "launchpad.net/juju-core/state/api" |
29 "launchpad.net/juju-core/state/api/params" | 30 "launchpad.net/juju-core/state/api/params" |
30 "launchpad.net/juju-core/utils" | 31 "launchpad.net/juju-core/utils" |
31 "net/http" | 32 "net/http" |
32 "strconv" | 33 "strconv" |
33 "strings" | 34 "strings" |
34 "sync" | 35 "sync" |
35 "time" | 36 "time" |
(...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
263 novaUnlocked *nova.Client | 264 novaUnlocked *nova.Client |
264 storageUnlocked environs.Storage | 265 storageUnlocked environs.Storage |
265 publicStorageUnlocked environs.StorageReader // optional. | 266 publicStorageUnlocked environs.StorageReader // optional. |
266 // An ordered list of paths in which to find the simplestreams index fil
es used to | 267 // An ordered list of paths in which to find the simplestreams index fil
es used to |
267 // look up image ids. | 268 // look up image ids. |
268 imageBaseURLs []string | 269 imageBaseURLs []string |
269 } | 270 } |
270 | 271 |
271 var _ environs.Environ = (*environ)(nil) | 272 var _ environs.Environ = (*environ)(nil) |
272 | 273 |
273 type instance struct { | 274 type openstackInstance struct { |
274 e *environ | 275 e *environ |
275 *nova.ServerDetail | 276 *nova.ServerDetail |
276 address string | 277 address string |
277 } | 278 } |
278 | 279 |
279 func (inst *instance) String() string { | 280 func (inst *openstackInstance) String() string { |
280 return inst.ServerDetail.Id | 281 return inst.ServerDetail.Id |
281 } | 282 } |
282 | 283 |
283 var _ environs.Instance = (*instance)(nil) | 284 var _ instance.Instance = (*openstackInstance)(nil) |
284 | 285 |
285 func (inst *instance) Id() state.InstanceId { | 286 func (inst *openstackInstance) Id() state.InstanceId { |
286 return state.InstanceId(inst.ServerDetail.Id) | 287 return state.InstanceId(inst.ServerDetail.Id) |
287 } | 288 } |
288 | 289 |
289 // instanceAddress processes a map of networks to lists of IP | 290 // instanceAddress processes a map of networks to lists of IP |
290 // addresses, as returned by Nova.GetServer(), extracting the proper | 291 // addresses, as returned by Nova.GetServer(), extracting the proper |
291 // public (or private, if public is not available) IPv4 address, and | 292 // public (or private, if public is not available) IPv4 address, and |
292 // returning it, or an error. | 293 // returning it, or an error. |
293 func instanceAddress(addresses map[string][]nova.IPAddress) (string, error) { | 294 func instanceAddress(addresses map[string][]nova.IPAddress) (string, error) { |
294 var private, public, privateNet string | 295 var private, public, privateNet string |
295 for network, ips := range addresses { | 296 for network, ips := range addresses { |
(...skipping 16 matching lines...) Expand all Loading... |
312 public = prv[1].Address | 313 public = prv[1].Address |
313 } | 314 } |
314 } | 315 } |
315 // Juju assumes it always needs a public address and loops waiting for o
ne. | 316 // Juju assumes it always needs a public address and loops waiting for o
ne. |
316 // In fact a private address is generally fine provided it can be sshed
to. | 317 // In fact a private address is generally fine provided it can be sshed
to. |
317 // (ported from py-juju/providers/openstack) | 318 // (ported from py-juju/providers/openstack) |
318 if public == "" && private != "" { | 319 if public == "" && private != "" { |
319 public = private | 320 public = private |
320 } | 321 } |
321 if public == "" { | 322 if public == "" { |
322 » » return "", environs.ErrNoDNSName | 323 » » return "", instance.ErrNoDNSName |
323 } | 324 } |
324 return public, nil | 325 return public, nil |
325 } | 326 } |
326 | 327 |
327 func (inst *instance) DNSName() (string, error) { | 328 func (inst *openstackInstance) DNSName() (string, error) { |
328 if inst.address != "" { | 329 if inst.address != "" { |
329 return inst.address, nil | 330 return inst.address, nil |
330 } | 331 } |
331 // Fetch the instance information again, in case | 332 // Fetch the instance information again, in case |
332 // the addresses have become available. | 333 // the addresses have become available. |
333 server, err := inst.e.nova().GetServer(string(inst.Id())) | 334 server, err := inst.e.nova().GetServer(string(inst.Id())) |
334 if err != nil { | 335 if err != nil { |
335 return "", err | 336 return "", err |
336 } | 337 } |
337 inst.address, err = instanceAddress(server.Addresses) | 338 inst.address, err = instanceAddress(server.Addresses) |
338 if err != nil { | 339 if err != nil { |
339 return "", err | 340 return "", err |
340 } | 341 } |
341 return inst.address, nil | 342 return inst.address, nil |
342 } | 343 } |
343 | 344 |
344 func (inst *instance) WaitDNSName() (string, error) { | 345 func (inst *openstackInstance) WaitDNSName() (string, error) { |
345 for a := longAttempt.Start(); a.Next(); { | 346 for a := longAttempt.Start(); a.Next(); { |
346 addr, err := inst.DNSName() | 347 addr, err := inst.DNSName() |
347 » » if err == nil || err != environs.ErrNoDNSName { | 348 » » if err == nil || err != instance.ErrNoDNSName { |
348 return addr, err | 349 return addr, err |
349 } | 350 } |
350 } | 351 } |
351 return "", fmt.Errorf("timed out trying to get DNS address for %v", inst
.Id()) | 352 return "", fmt.Errorf("timed out trying to get DNS address for %v", inst
.Id()) |
352 } | 353 } |
353 | 354 |
354 // TODO: following 30 lines nearly verbatim from environs/ec2 | 355 // TODO: following 30 lines nearly verbatim from environs/ec2 |
355 | 356 |
356 func (inst *instance) OpenPorts(machineId string, ports []params.Port) error { | 357 func (inst *openstackInstance) OpenPorts(machineId string, ports []params.Port)
error { |
357 if inst.e.Config().FirewallMode() != config.FwInstance { | 358 if inst.e.Config().FirewallMode() != config.FwInstance { |
358 return fmt.Errorf("invalid firewall mode for opening ports on in
stance: %q", | 359 return fmt.Errorf("invalid firewall mode for opening ports on in
stance: %q", |
359 inst.e.Config().FirewallMode()) | 360 inst.e.Config().FirewallMode()) |
360 } | 361 } |
361 name := inst.e.machineGroupName(machineId) | 362 name := inst.e.machineGroupName(machineId) |
362 if err := inst.e.openPortsInGroup(name, ports); err != nil { | 363 if err := inst.e.openPortsInGroup(name, ports); err != nil { |
363 return err | 364 return err |
364 } | 365 } |
365 log.Infof("environs/openstack: opened ports in security group %s: %v", n
ame, ports) | 366 log.Infof("environs/openstack: opened ports in security group %s: %v", n
ame, ports) |
366 return nil | 367 return nil |
367 } | 368 } |
368 | 369 |
369 func (inst *instance) ClosePorts(machineId string, ports []params.Port) error { | 370 func (inst *openstackInstance) ClosePorts(machineId string, ports []params.Port)
error { |
370 if inst.e.Config().FirewallMode() != config.FwInstance { | 371 if inst.e.Config().FirewallMode() != config.FwInstance { |
371 return fmt.Errorf("invalid firewall mode for closing ports on in
stance: %q", | 372 return fmt.Errorf("invalid firewall mode for closing ports on in
stance: %q", |
372 inst.e.Config().FirewallMode()) | 373 inst.e.Config().FirewallMode()) |
373 } | 374 } |
374 name := inst.e.machineGroupName(machineId) | 375 name := inst.e.machineGroupName(machineId) |
375 if err := inst.e.closePortsInGroup(name, ports); err != nil { | 376 if err := inst.e.closePortsInGroup(name, ports); err != nil { |
376 return err | 377 return err |
377 } | 378 } |
378 log.Infof("environs/openstack: closed ports in security group %s: %v", n
ame, ports) | 379 log.Infof("environs/openstack: closed ports in security group %s: %v", n
ame, ports) |
379 return nil | 380 return nil |
380 } | 381 } |
381 | 382 |
382 func (inst *instance) Ports(machineId string) ([]params.Port, error) { | 383 func (inst *openstackInstance) Ports(machineId string) ([]params.Port, error) { |
383 if inst.e.Config().FirewallMode() != config.FwInstance { | 384 if inst.e.Config().FirewallMode() != config.FwInstance { |
384 return nil, fmt.Errorf("invalid firewall mode for retrieving por
ts from instance: %q", | 385 return nil, fmt.Errorf("invalid firewall mode for retrieving por
ts from instance: %q", |
385 inst.e.Config().FirewallMode()) | 386 inst.e.Config().FirewallMode()) |
386 } | 387 } |
387 name := inst.e.machineGroupName(machineId) | 388 name := inst.e.machineGroupName(machineId) |
388 return inst.e.portsInGroup(name) | 389 return inst.e.portsInGroup(name) |
389 } | 390 } |
390 | 391 |
391 func (e *environ) ecfg() *environConfig { | 392 func (e *environ) ecfg() *environConfig { |
392 e.ecfgMutex.Lock() | 393 e.ecfgMutex.Lock() |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
500 }) | 501 }) |
501 if err != nil { | 502 if err != nil { |
502 return fmt.Errorf("cannot start bootstrap instance: %v", err) | 503 return fmt.Errorf("cannot start bootstrap instance: %v", err) |
503 } | 504 } |
504 err = e.saveState(&bootstrapState{ | 505 err = e.saveState(&bootstrapState{ |
505 StateInstances: []state.InstanceId{inst.Id()}, | 506 StateInstances: []state.InstanceId{inst.Id()}, |
506 }) | 507 }) |
507 if err != nil { | 508 if err != nil { |
508 // ignore error on StopInstance because the previous error is | 509 // ignore error on StopInstance because the previous error is |
509 // more important. | 510 // more important. |
510 » » e.StopInstances([]environs.Instance{inst}) | 511 » » e.StopInstances([]instance.Instance{inst}) |
511 return fmt.Errorf("cannot save state: %v", err) | 512 return fmt.Errorf("cannot save state: %v", err) |
512 } | 513 } |
513 // TODO make safe in the case of racing Bootstraps | 514 // TODO make safe in the case of racing Bootstraps |
514 // If two Bootstraps are called concurrently, there's | 515 // If two Bootstraps are called concurrently, there's |
515 // no way to use Swift to make sure that only one succeeds. | 516 // no way to use Swift to make sure that only one succeeds. |
516 // Perhaps consider using SimpleDB for state storage | 517 // Perhaps consider using SimpleDB for state storage |
517 // which would enable that possibility. | 518 // which would enable that possibility. |
518 | 519 |
519 return nil | 520 return nil |
520 } | 521 } |
(...skipping 17 matching lines...) Expand all Loading... |
538 insts, err := e.Instances(st.StateInstances) | 539 insts, err := e.Instances(st.StateInstances) |
539 if err != nil && err != environs.ErrPartialInstances { | 540 if err != nil && err != environs.ErrPartialInstances { |
540 log.Debugf("error getting state instance: %v", err.Error
()) | 541 log.Debugf("error getting state instance: %v", err.Error
()) |
541 return nil, nil, err | 542 return nil, nil, err |
542 } | 543 } |
543 log.Debugf("started processing instances: %#v", insts) | 544 log.Debugf("started processing instances: %#v", insts) |
544 for _, inst := range insts { | 545 for _, inst := range insts { |
545 if inst == nil { | 546 if inst == nil { |
546 continue | 547 continue |
547 } | 548 } |
548 » » » name, err := inst.(*instance).DNSName() | 549 » » » name, err := inst.(*openstackInstance).DNSName() |
549 if err != nil { | 550 if err != nil { |
550 continue | 551 continue |
551 } | 552 } |
552 if name != "" { | 553 if name != "" { |
553 statePortSuffix := fmt.Sprintf(":%d", config.Sta
tePort()) | 554 statePortSuffix := fmt.Sprintf(":%d", config.Sta
tePort()) |
554 apiPortSuffix := fmt.Sprintf(":%d", config.APIPo
rt()) | 555 apiPortSuffix := fmt.Sprintf(":%d", config.APIPo
rt()) |
555 stateAddrs = append(stateAddrs, name+statePortSu
ffix) | 556 stateAddrs = append(stateAddrs, name+statePortSu
ffix) |
556 apiAddrs = append(apiAddrs, name+apiPortSuffix) | 557 apiAddrs = append(apiAddrs, name+apiPortSuffix) |
557 } | 558 } |
558 } | 559 } |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
650 productStreamsURL, err := e.client.MakeServiceURL("product-streams", nil
) | 651 productStreamsURL, err := e.client.MakeServiceURL("product-streams", nil
) |
651 if err == nil { | 652 if err == nil { |
652 e.imageBaseURLs = append(e.imageBaseURLs, productStreamsURL) | 653 e.imageBaseURLs = append(e.imageBaseURLs, productStreamsURL) |
653 } | 654 } |
654 // Add the default simplestreams base URL. | 655 // Add the default simplestreams base URL. |
655 e.imageBaseURLs = append(e.imageBaseURLs, imagemetadata.DefaultBaseURL) | 656 e.imageBaseURLs = append(e.imageBaseURLs, imagemetadata.DefaultBaseURL) |
656 | 657 |
657 return e.imageBaseURLs, nil | 658 return e.imageBaseURLs, nil |
658 } | 659 } |
659 | 660 |
660 func (e *environ) StartInstance(machineId, machineNonce string, series string, c
ons constraints.Value, info *state.Info, apiInfo *api.Info) (environs.Instance,
error) { | 661 func (e *environ) StartInstance(machineId, machineNonce string, series string, c
ons constraints.Value, info *state.Info, apiInfo *api.Info) (instance.Instance,
error) { |
661 possibleTools, err := environs.FindInstanceTools(e, series, cons) | 662 possibleTools, err := environs.FindInstanceTools(e, series, cons) |
662 if err != nil { | 663 if err != nil { |
663 return nil, err | 664 return nil, err |
664 } | 665 } |
665 return e.startInstance(&startInstanceParams{ | 666 return e.startInstance(&startInstanceParams{ |
666 machineId: machineId, | 667 machineId: machineId, |
667 machineNonce: machineNonce, | 668 machineNonce: machineNonce, |
668 series: series, | 669 series: series, |
669 constraints: cons, | 670 constraints: cons, |
670 info: info, | 671 info: info, |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
760 err = e.nova().AddServerFloatingIP(serverId, fip.IP) | 761 err = e.nova().AddServerFloatingIP(serverId, fip.IP) |
761 if err == nil { | 762 if err == nil { |
762 return nil | 763 return nil |
763 } | 764 } |
764 } | 765 } |
765 return err | 766 return err |
766 } | 767 } |
767 | 768 |
768 // startInstance is the internal version of StartInstance, used by Bootstrap | 769 // startInstance is the internal version of StartInstance, used by Bootstrap |
769 // as well as via StartInstance itself. | 770 // as well as via StartInstance itself. |
770 func (e *environ) startInstance(scfg *startInstanceParams) (environs.Instance, e
rror) { | 771 func (e *environ) startInstance(scfg *startInstanceParams) (instance.Instance, e
rror) { |
771 series := scfg.possibleTools.Series() | 772 series := scfg.possibleTools.Series() |
772 if len(series) != 1 { | 773 if len(series) != 1 { |
773 return nil, fmt.Errorf("expected single series, got %v", series) | 774 return nil, fmt.Errorf("expected single series, got %v", series) |
774 } | 775 } |
775 if series[0] != scfg.series { | 776 if series[0] != scfg.series { |
776 return nil, fmt.Errorf("tools mismatch: expected series %v, got
%v", series, series[0]) | 777 return nil, fmt.Errorf("tools mismatch: expected series %v, got
%v", series, series[0]) |
777 } | 778 } |
778 arches := scfg.possibleTools.Arches() | 779 arches := scfg.possibleTools.Arches() |
779 spec, err := findInstanceSpec(e, &instances.InstanceConstraint{ | 780 spec, err := findInstanceSpec(e, &instances.InstanceConstraint{ |
780 Region: e.ecfg().region(), | 781 Region: e.ecfg().region(), |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
825 break | 826 break |
826 } | 827 } |
827 } | 828 } |
828 if err != nil { | 829 if err != nil { |
829 return nil, fmt.Errorf("cannot run instance: %v", err) | 830 return nil, fmt.Errorf("cannot run instance: %v", err) |
830 } | 831 } |
831 detail, err := e.nova().GetServer(server.Id) | 832 detail, err := e.nova().GetServer(server.Id) |
832 if err != nil { | 833 if err != nil { |
833 return nil, fmt.Errorf("cannot get started instance: %v", err) | 834 return nil, fmt.Errorf("cannot get started instance: %v", err) |
834 } | 835 } |
835 » inst := &instance{e, detail, ""} | 836 » inst := &openstackInstance{e, detail, ""} |
836 log.Infof("environs/openstack: started instance %q", inst.Id()) | 837 log.Infof("environs/openstack: started instance %q", inst.Id()) |
837 if scfg.withPublicIP { | 838 if scfg.withPublicIP { |
838 if err := e.assignPublicIP(publicIP, string(inst.Id())); err !=
nil { | 839 if err := e.assignPublicIP(publicIP, string(inst.Id())); err !=
nil { |
839 if err := e.terminateInstances([]state.InstanceId{inst.I
d()}); err != nil { | 840 if err := e.terminateInstances([]state.InstanceId{inst.I
d()}); err != nil { |
840 // ignore the failure at this stage, just log it | 841 // ignore the failure at this stage, just log it |
841 log.Debugf("environs/openstack: failed to termin
ate instance %q: %v", inst.Id(), err) | 842 log.Debugf("environs/openstack: failed to termin
ate instance %q: %v", inst.Id(), err) |
842 } | 843 } |
843 return nil, fmt.Errorf("cannot assign public address %s
to instance %q: %v", publicIP.IP, inst.Id(), err) | 844 return nil, fmt.Errorf("cannot assign public address %s
to instance %q: %v", publicIP.IP, inst.Id(), err) |
844 } | 845 } |
845 log.Infof("environs/openstack: assigned public IP %s to %q", pub
licIP.IP, inst.Id()) | 846 log.Infof("environs/openstack: assigned public IP %s to %q", pub
licIP.IP, inst.Id()) |
846 } | 847 } |
847 return inst, nil | 848 return inst, nil |
848 } | 849 } |
849 | 850 |
850 func (e *environ) StopInstances(insts []environs.Instance) error { | 851 func (e *environ) StopInstances(insts []instance.Instance) error { |
851 ids := make([]state.InstanceId, len(insts)) | 852 ids := make([]state.InstanceId, len(insts)) |
852 for i, inst := range insts { | 853 for i, inst := range insts { |
853 » » instanceValue, ok := inst.(*instance) | 854 » » instanceValue, ok := inst.(*openstackInstance) |
854 if !ok { | 855 if !ok { |
855 » » » return errors.New("Incompatible environs.Instance suppli
ed") | 856 » » » return errors.New("Incompatible instance.Instance suppli
ed") |
856 } | 857 } |
857 ids[i] = instanceValue.Id() | 858 ids[i] = instanceValue.Id() |
858 } | 859 } |
859 log.Debugf("environs/openstack: terminating instances %v", ids) | 860 log.Debugf("environs/openstack: terminating instances %v", ids) |
860 return e.terminateInstances(ids) | 861 return e.terminateInstances(ids) |
861 } | 862 } |
862 | 863 |
863 // collectInstances tries to get information on each instance id in ids. | 864 // collectInstances tries to get information on each instance id in ids. |
864 // It fills the slots in the given map for known servers with status | 865 // It fills the slots in the given map for known servers with status |
865 // either ACTIVE or BUILD. Returns a list of missing ids. | 866 // either ACTIVE or BUILD. Returns a list of missing ids. |
866 func (e *environ) collectInstances(ids []state.InstanceId, out map[state.Instanc
eId]environs.Instance) []state.InstanceId { | 867 func (e *environ) collectInstances(ids []state.InstanceId, out map[state.Instanc
eId]instance.Instance) []state.InstanceId { |
867 var err error | 868 var err error |
868 serversById := make(map[string]nova.ServerDetail) | 869 serversById := make(map[string]nova.ServerDetail) |
869 if len(ids) == 1 { | 870 if len(ids) == 1 { |
870 // most common case - single instance | 871 // most common case - single instance |
871 var server *nova.ServerDetail | 872 var server *nova.ServerDetail |
872 server, err = e.nova().GetServer(string(ids[0])) | 873 server, err = e.nova().GetServer(string(ids[0])) |
873 if server != nil { | 874 if server != nil { |
874 serversById[server.Id] = *server | 875 serversById[server.Id] = *server |
875 } | 876 } |
876 } else { | 877 } else { |
877 var servers []nova.ServerDetail | 878 var servers []nova.ServerDetail |
878 servers, err = e.nova().ListServersDetail(e.machinesFilter()) | 879 servers, err = e.nova().ListServersDetail(e.machinesFilter()) |
879 for _, server := range servers { | 880 for _, server := range servers { |
880 serversById[server.Id] = server | 881 serversById[server.Id] = server |
881 } | 882 } |
882 } | 883 } |
883 if err != nil { | 884 if err != nil { |
884 return ids | 885 return ids |
885 } | 886 } |
886 var missing []state.InstanceId | 887 var missing []state.InstanceId |
887 for _, id := range ids { | 888 for _, id := range ids { |
888 if server, found := serversById[string(id)]; found { | 889 if server, found := serversById[string(id)]; found { |
889 if server.Status == nova.StatusActive || server.Status =
= nova.StatusBuild { | 890 if server.Status == nova.StatusActive || server.Status =
= nova.StatusBuild { |
890 » » » » out[id] = &instance{e, &server, ""} | 891 » » » » out[id] = &openstackInstance{e, &server, ""} |
891 } | 892 } |
892 continue | 893 continue |
893 } | 894 } |
894 missing = append(missing, id) | 895 missing = append(missing, id) |
895 } | 896 } |
896 return missing | 897 return missing |
897 } | 898 } |
898 | 899 |
899 func (e *environ) Instances(ids []state.InstanceId) ([]environs.Instance, error)
{ | 900 func (e *environ) Instances(ids []state.InstanceId) ([]instance.Instance, error)
{ |
900 if len(ids) == 0 { | 901 if len(ids) == 0 { |
901 return nil, nil | 902 return nil, nil |
902 } | 903 } |
903 missing := ids | 904 missing := ids |
904 » found := make(map[state.InstanceId]environs.Instance) | 905 » found := make(map[state.InstanceId]instance.Instance) |
905 // Make a series of requests to cope with eventual consistency. | 906 // Make a series of requests to cope with eventual consistency. |
906 // Each request will attempt to add more instances to the requested | 907 // Each request will attempt to add more instances to the requested |
907 // set. | 908 // set. |
908 for a := shortAttempt.Start(); a.Next(); { | 909 for a := shortAttempt.Start(); a.Next(); { |
909 if missing = e.collectInstances(missing, found); len(missing) ==
0 { | 910 if missing = e.collectInstances(missing, found); len(missing) ==
0 { |
910 break | 911 break |
911 } | 912 } |
912 } | 913 } |
913 if len(found) == 0 { | 914 if len(found) == 0 { |
914 return nil, environs.ErrNoInstances | 915 return nil, environs.ErrNoInstances |
915 } | 916 } |
916 » insts := make([]environs.Instance, len(ids)) | 917 » insts := make([]instance.Instance, len(ids)) |
917 var err error | 918 var err error |
918 for i, id := range ids { | 919 for i, id := range ids { |
919 if inst := found[id]; inst != nil { | 920 if inst := found[id]; inst != nil { |
920 insts[i] = inst | 921 insts[i] = inst |
921 } else { | 922 } else { |
922 err = environs.ErrPartialInstances | 923 err = environs.ErrPartialInstances |
923 } | 924 } |
924 } | 925 } |
925 return insts, err | 926 return insts, err |
926 } | 927 } |
927 | 928 |
928 func (e *environ) AllInstances() (insts []environs.Instance, err error) { | 929 func (e *environ) AllInstances() (insts []instance.Instance, err error) { |
929 servers, err := e.nova().ListServersDetail(e.machinesFilter()) | 930 servers, err := e.nova().ListServersDetail(e.machinesFilter()) |
930 if err != nil { | 931 if err != nil { |
931 return nil, err | 932 return nil, err |
932 } | 933 } |
933 for _, server := range servers { | 934 for _, server := range servers { |
934 if server.Status == nova.StatusActive || server.Status == nova.S
tatusBuild { | 935 if server.Status == nova.StatusActive || server.Status == nova.S
tatusBuild { |
935 var s = server | 936 var s = server |
936 » » » insts = append(insts, &instance{e, &s, ""}) | 937 » » » insts = append(insts, &openstackInstance{e, &s, ""}) |
937 } | 938 } |
938 } | 939 } |
939 return insts, err | 940 return insts, err |
940 } | 941 } |
941 | 942 |
942 func (e *environ) Destroy(ensureInsts []environs.Instance) error { | 943 func (e *environ) Destroy(ensureInsts []instance.Instance) error { |
943 log.Infof("environs/openstack: destroying environment %q", e.name) | 944 log.Infof("environs/openstack: destroying environment %q", e.name) |
944 insts, err := e.AllInstances() | 945 insts, err := e.AllInstances() |
945 if err != nil { | 946 if err != nil { |
946 return fmt.Errorf("cannot get instances: %v", err) | 947 return fmt.Errorf("cannot get instances: %v", err) |
947 } | 948 } |
948 found := make(map[state.InstanceId]bool) | 949 found := make(map[state.InstanceId]bool) |
949 var ids []state.InstanceId | 950 var ids []state.InstanceId |
950 for _, inst := range insts { | 951 for _, inst := range insts { |
951 ids = append(ids, inst.Id()) | 952 ids = append(ids, inst.Id()) |
952 found[inst.Id()] = true | 953 found[inst.Id()] = true |
953 } | 954 } |
954 | 955 |
955 // Add any instances we've been told about but haven't yet shown | 956 // Add any instances we've been told about but haven't yet shown |
956 // up in the instance list. | 957 // up in the instance list. |
957 for _, inst := range ensureInsts { | 958 for _, inst := range ensureInsts { |
958 » » id := state.InstanceId(inst.(*instance).Id()) | 959 » » id := state.InstanceId(inst.(*openstackInstance).Id()) |
959 if !found[id] { | 960 if !found[id] { |
960 ids = append(ids, id) | 961 ids = append(ids, id) |
961 found[id] = true | 962 found[id] = true |
962 } | 963 } |
963 } | 964 } |
964 err = e.terminateInstances(ids) | 965 err = e.terminateInstances(ids) |
965 if err != nil { | 966 if err != nil { |
966 return err | 967 return err |
967 } | 968 } |
968 | 969 |
(...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1196 if gooseerrors.IsNotFound(err) { | 1197 if gooseerrors.IsNotFound(err) { |
1197 err = nil | 1198 err = nil |
1198 } | 1199 } |
1199 if err != nil && firstErr == nil { | 1200 if err != nil && firstErr == nil { |
1200 log.Debugf("environs/openstack: error terminating instan
ce %q: %v", id, err) | 1201 log.Debugf("environs/openstack: error terminating instan
ce %q: %v", id, err) |
1201 firstErr = err | 1202 firstErr = err |
1202 } | 1203 } |
1203 } | 1204 } |
1204 return firstErr | 1205 return firstErr |
1205 } | 1206 } |
OLD | NEW |