| Left: | ||
| Right: |
| OLD | NEW |
|---|---|
| 1 package ec2 | 1 package ec2 |
| 2 | 2 |
| 3 import ( | 3 import ( |
| 4 "fmt" | 4 "fmt" |
| 5 "launchpad.net/goamz/aws" | 5 "launchpad.net/goamz/aws" |
| 6 "launchpad.net/goamz/ec2" | 6 "launchpad.net/goamz/ec2" |
| 7 "launchpad.net/goamz/s3" | 7 "launchpad.net/goamz/s3" |
| 8 "launchpad.net/juju-core/environs" | 8 "launchpad.net/juju-core/environs" |
| 9 "launchpad.net/juju-core/environs/config" | 9 "launchpad.net/juju-core/environs/config" |
| 10 "launchpad.net/juju-core/log" | 10 "launchpad.net/juju-core/log" |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 32 Total: 3 * time.Minute, | 32 Total: 3 * time.Minute, |
| 33 Delay: 1 * time.Second, | 33 Delay: 1 * time.Second, |
| 34 } | 34 } |
| 35 | 35 |
| 36 func init() { | 36 func init() { |
| 37 environs.RegisterProvider("ec2", environProvider{}) | 37 environs.RegisterProvider("ec2", environProvider{}) |
| 38 } | 38 } |
| 39 | 39 |
| 40 type environProvider struct{} | 40 type environProvider struct{} |
| 41 | 41 |
| 42 var _ environs.EnvironProvider = environProvider{} | 42 var providerInstance environProvider |
| 43 | 43 |
| 44 type environ struct { | 44 type environ struct { |
| 45 name string | 45 name string |
| 46 | 46 |
| 47 » // configMutex protects the *Unlocked fields below. | 47 » // ecfgMutex protects the *Unlocked fields below. |
| 48 » configMutex sync.Mutex | 48 » ecfgMutex sync.Mutex |
| 49 » configUnlocked *providerConfig | 49 » ecfgUnlocked *environConfig |
| 50 ec2Unlocked *ec2.EC2 | 50 ec2Unlocked *ec2.EC2 |
| 51 s3Unlocked *s3.S3 | 51 s3Unlocked *s3.S3 |
| 52 storageUnlocked *storage | 52 storageUnlocked *storage |
| 53 publicStorageUnlocked *storage // optional. | 53 publicStorageUnlocked *storage // optional. |
| 54 } | 54 } |
| 55 | 55 |
| 56 var _ environs.Environ = (*environ)(nil) | 56 var _ environs.Environ = (*environ)(nil) |
| 57 | 57 |
| 58 type instance struct { | 58 type instance struct { |
| 59 e *environ | 59 e *environ |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 102 log.Printf("environs/ec2: opening environment %q", cfg.Name()) | 102 log.Printf("environs/ec2: opening environment %q", cfg.Name()) |
| 103 e := new(environ) | 103 e := new(environ) |
| 104 err := e.SetConfig(cfg) | 104 err := e.SetConfig(cfg) |
| 105 if err != nil { | 105 if err != nil { |
| 106 return nil, err | 106 return nil, err |
| 107 } | 107 } |
| 108 return e, nil | 108 return e, nil |
| 109 } | 109 } |
| 110 | 110 |
| 111 func (e *environ) SetConfig(cfg *config.Config) error { | 111 func (e *environ) SetConfig(cfg *config.Config) error { |
| 112 » config, err := newConfig(cfg) | 112 » ecfg, err := providerInstance.newConfig(cfg) |
| 113 if err != nil { | 113 if err != nil { |
| 114 return err | 114 return err |
| 115 } | 115 } |
| 116 » if aws.Regions[config.region].EC2Endpoint == "" { | 116 » e.ecfgMutex.Lock() |
| 117 » » return fmt.Errorf("environment %q references unknown EC2 region %q", config.name, config.region) | 117 » defer e.ecfgMutex.Unlock() |
|
fwereade
2012/07/20 14:25:08
...but I guess it's not worth checking for. I alwa
niemeyer
2012/07/20 18:14:45
Agreed.
| |
| 118 » } | 118 » e.name = ecfg.Name() |
| 119 » e.configMutex.Lock() | 119 » e.ecfgUnlocked = ecfg |
| 120 » defer e.configMutex.Unlock() | 120 |
| 121 » // TODO(dfc) bug #1018207, renaming an environment once it is in use sho uld be forbidden | 121 » auth := aws.Auth{ecfg.accessKey(), ecfg.secretKey()} |
| 122 » e.name = config.name | 122 » region := aws.Regions[ecfg.region()] |
| 123 » e.configUnlocked = config | 123 » e.ec2Unlocked = ec2.New(auth, region) |
| 124 » e.ec2Unlocked = ec2.New(config.auth, aws.Regions[config.region]) | 124 » e.s3Unlocked = s3.New(auth, region) |
| 125 » e.s3Unlocked = s3.New(config.auth, aws.Regions[config.region]) | |
| 126 | 125 |
| 127 // create new storage instances, existing instances continue | 126 // create new storage instances, existing instances continue |
| 128 // to reference their existing configuration. | 127 // to reference their existing configuration. |
| 129 e.storageUnlocked = &storage{ | 128 e.storageUnlocked = &storage{ |
| 130 » » bucket: e.s3Unlocked.Bucket(config.bucket), | 129 » » bucket: e.s3Unlocked.Bucket(ecfg.controlBucket()), |
| 131 } | 130 } |
| 132 » if config.publicBucket != "" { | 131 » if ecfg.publicBucket() != "" { |
| 133 e.publicStorageUnlocked = &storage{ | 132 e.publicStorageUnlocked = &storage{ |
| 134 » » » bucket: e.s3Unlocked.Bucket(config.publicBucket), | 133 » » » bucket: e.s3Unlocked.Bucket(ecfg.publicBucket()), |
| 135 } | 134 } |
| 136 } else { | 135 } else { |
| 137 e.publicStorageUnlocked = nil | 136 e.publicStorageUnlocked = nil |
| 138 } | 137 } |
| 139 return nil | 138 return nil |
| 140 } | 139 } |
| 141 | 140 |
| 142 func (e *environ) config() *providerConfig { | 141 func (e *environ) ecfg() *environConfig { |
| 143 » e.configMutex.Lock() | 142 » e.ecfgMutex.Lock() |
| 144 » defer e.configMutex.Unlock() | 143 » ecfg := e.ecfgUnlocked |
| 145 » return e.configUnlocked | 144 » e.ecfgMutex.Unlock() |
| 145 » return ecfg | |
| 146 } | 146 } |
| 147 | 147 |
| 148 func (e *environ) ec2() *ec2.EC2 { | 148 func (e *environ) ec2() *ec2.EC2 { |
| 149 » e.configMutex.Lock() | 149 » e.ecfgMutex.Lock() |
| 150 » defer e.configMutex.Unlock() | 150 » ec2 := e.ec2Unlocked |
| 151 » return e.ec2Unlocked | 151 » e.ecfgMutex.Unlock() |
| 152 » return ec2 | |
| 152 } | 153 } |
| 153 | 154 |
| 154 func (e *environ) s3() *s3.S3 { | 155 func (e *environ) s3() *s3.S3 { |
| 155 » e.configMutex.Lock() | 156 » e.ecfgMutex.Lock() |
| 156 » defer e.configMutex.Unlock() | 157 » s3 := e.s3Unlocked |
| 157 » return e.s3Unlocked | 158 » e.ecfgMutex.Unlock() |
| 159 » return s3 | |
| 158 } | 160 } |
| 159 | 161 |
| 160 func (e *environ) Name() string { | 162 func (e *environ) Name() string { |
| 161 » return e.config().name | 163 » return e.name |
| 162 } | 164 } |
| 163 | 165 |
| 164 func (e *environ) Storage() environs.Storage { | 166 func (e *environ) Storage() environs.Storage { |
| 165 » e.configMutex.Lock() | 167 » e.ecfgMutex.Lock() |
| 166 » defer e.configMutex.Unlock() | 168 » storage := e.storageUnlocked |
| 167 » return e.storageUnlocked | 169 » e.ecfgMutex.Unlock() |
| 170 » return storage | |
| 168 } | 171 } |
| 169 | 172 |
| 170 func (e *environ) PublicStorage() environs.StorageReader { | 173 func (e *environ) PublicStorage() environs.StorageReader { |
| 171 » e.configMutex.Lock() | 174 » e.ecfgMutex.Lock() |
| 172 » defer e.configMutex.Unlock() | 175 » defer e.ecfgMutex.Unlock() |
| 173 if e.publicStorageUnlocked == nil { | 176 if e.publicStorageUnlocked == nil { |
| 174 return environs.EmptyStorage | 177 return environs.EmptyStorage |
| 175 } | 178 } |
| 176 return e.publicStorageUnlocked | 179 return e.publicStorageUnlocked |
| 177 } | 180 } |
| 178 | 181 |
| 179 func (e *environ) Bootstrap(uploadTools bool) error { | 182 func (e *environ) Bootstrap(uploadTools bool) error { |
| 180 log.Printf("environs/ec2: bootstrapping environment %q", e.name) | 183 log.Printf("environs/ec2: bootstrapping environment %q", e.name) |
| 181 _, err := e.loadState() | 184 _, err := e.loadState() |
| 182 if err == nil { | 185 if err == nil { |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 259 | 262 |
| 260 func (e *environ) userData(machineId int, info *state.Info, master bool, toolsUR L string) ([]byte, error) { | 263 func (e *environ) userData(machineId int, info *state.Info, master bool, toolsUR L string) ([]byte, error) { |
| 261 cfg := &machineConfig{ | 264 cfg := &machineConfig{ |
| 262 provisioner: master, | 265 provisioner: master, |
| 263 zookeeper: master, | 266 zookeeper: master, |
| 264 stateInfo: info, | 267 stateInfo: info, |
| 265 instanceIdAccessor: "$(curl http://169.254.169.254/1.0/meta-data /instance-id)", | 268 instanceIdAccessor: "$(curl http://169.254.169.254/1.0/meta-data /instance-id)", |
| 266 providerType: "ec2", | 269 providerType: "ec2", |
| 267 toolsURL: toolsURL, | 270 toolsURL: toolsURL, |
| 268 machineId: machineId, | 271 machineId: machineId, |
| 269 » » authorizedKeys: e.config().AuthorizedKeys(), | 272 » » authorizedKeys: e.ecfg().AuthorizedKeys(), |
| 270 } | 273 } |
| 271 cloudcfg, err := newCloudInit(cfg) | 274 cloudcfg, err := newCloudInit(cfg) |
| 272 if err != nil { | 275 if err != nil { |
| 273 return nil, err | 276 return nil, err |
| 274 } | 277 } |
| 275 return cloudcfg.Render() | 278 return cloudcfg.Render() |
| 276 } | 279 } |
| 277 | 280 |
| 278 // startInstance is the internal version of StartInstance, used by Bootstrap | 281 // startInstance is the internal version of StartInstance, used by Bootstrap |
| 279 // as well as via StartInstance itself. If master is true, a bootstrap | 282 // as well as via StartInstance itself. If master is true, a bootstrap |
| 280 // instance will be started. | 283 // instance will be started. |
| 281 func (e *environ) startInstance(machineId int, info *state.Info, master bool) (e nvirons.Instance, error) { | 284 func (e *environ) startInstance(machineId int, info *state.Info, master bool) (e nvirons.Instance, error) { |
| 282 spec, err := findInstanceSpec(&instanceConstraint{ | 285 spec, err := findInstanceSpec(&instanceConstraint{ |
| 283 series: config.CurrentSeries, | 286 series: config.CurrentSeries, |
| 284 arch: config.CurrentArch, | 287 arch: config.CurrentArch, |
| 285 » » region: e.config().region, | 288 » » region: e.ecfg().region(), |
| 286 }) | 289 }) |
| 287 if err != nil { | 290 if err != nil { |
| 288 return nil, fmt.Errorf("cannot find image satisfying constraints : %v", err) | 291 return nil, fmt.Errorf("cannot find image satisfying constraints : %v", err) |
| 289 } | 292 } |
| 290 log.Debugf("looking for tools for version %v; instance spec %#v", versio n.Current, spec) | 293 log.Debugf("looking for tools for version %v; instance spec %#v", versio n.Current, spec) |
| 291 toolsURL, err := environs.FindTools(e, version.Current, spec.series, spe c.arch) | 294 toolsURL, err := environs.FindTools(e, version.Current, spec.series, spe c.arch) |
| 292 if err != nil { | 295 if err != nil { |
| 293 return nil, fmt.Errorf("cannot find juju tools that would work o n the specified instance: %v", err) | 296 return nil, fmt.Errorf("cannot find juju tools that would work o n the specified instance: %v", err) |
| 294 } | 297 } |
| 295 userData, err := e.userData(machineId, info, master, toolsURL) | 298 userData, err := e.userData(machineId, info, master, toolsURL) |
| (...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 452 id := inst.(*instance).InstanceId | 455 id := inst.(*instance).InstanceId |
| 453 if !found[id] { | 456 if !found[id] { |
| 454 ids = append(ids, id) | 457 ids = append(ids, id) |
| 455 found[id] = true | 458 found[id] = true |
| 456 } | 459 } |
| 457 } | 460 } |
| 458 err = e.terminateInstances(ids) | 461 err = e.terminateInstances(ids) |
| 459 if err != nil { | 462 if err != nil { |
| 460 return err | 463 return err |
| 461 } | 464 } |
| 462 » // to properly observe e.storageUnlocked we need to get it's value while | 465 |
| 463 » // holding e.configMutex. e.Storage() does this for us, then we convert | 466 » // To properly observe e.storageUnlocked we need to get its value while |
| 467 » // holding e.ecfgMutex. e.Storage() does this for us, then we convert | |
| 464 // back to the (*storage) to access the private deleteAll() method. | 468 // back to the (*storage) to access the private deleteAll() method. |
| 465 st := e.Storage().(*storage) | 469 st := e.Storage().(*storage) |
| 466 err = st.deleteAll() | 470 err = st.deleteAll() |
| 467 if err != nil { | 471 if err != nil { |
| 468 return err | 472 return err |
| 469 } | 473 } |
| 470 return nil | 474 return nil |
| 471 } | 475 } |
| 472 | 476 |
| 473 func (e *environ) terminateInstances(ids []string) error { | 477 func (e *environ) terminateInstances(ids []string) error { |
| 474 if len(ids) == 0 { | 478 if len(ids) == 0 { |
| 475 return nil | 479 return nil |
| 476 } | 480 } |
| 477 var err error | 481 var err error |
| 478 ec2inst := e.ec2() | 482 ec2inst := e.ec2() |
| 479 for a := shortAttempt.Start(); a.Next(); { | 483 for a := shortAttempt.Start(); a.Next(); { |
| 480 _, err = ec2inst.TerminateInstances(ids) | 484 _, err = ec2inst.TerminateInstances(ids) |
| 481 if err == nil || ec2ErrCode(err) != "InvalidInstanceID.NotFound" { | 485 if err == nil || ec2ErrCode(err) != "InvalidInstanceID.NotFound" { |
| 482 return err | 486 return err |
| 483 } | 487 } |
| 484 } | 488 } |
| 485 if len(ids) == 1 { | 489 if len(ids) == 1 { |
| 486 return err | 490 return err |
| 487 } | 491 } |
| 488 var firstErr error | |
| 489 // If we get a NotFound error, it means that no instances have been | 492 // If we get a NotFound error, it means that no instances have been |
| 490 // terminated even if some exist, so try them one by one, ignoring | 493 // terminated even if some exist, so try them one by one, ignoring |
| 491 // NotFound errors. | 494 // NotFound errors. |
| 495 var firstErr error | |
| 492 for _, id := range ids { | 496 for _, id := range ids { |
| 493 _, err = ec2inst.TerminateInstances([]string{id}) | 497 _, err = ec2inst.TerminateInstances([]string{id}) |
| 494 if ec2ErrCode(err) == "InvalidInstanceID.NotFound" { | 498 if ec2ErrCode(err) == "InvalidInstanceID.NotFound" { |
| 495 err = nil | 499 err = nil |
| 496 } | 500 } |
| 497 if err != nil && firstErr == nil { | 501 if err != nil && firstErr == nil { |
| 498 firstErr = err | 502 firstErr = err |
| 499 } | 503 } |
| 500 } | 504 } |
| 501 return firstErr | 505 return firstErr |
| (...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 737 | 741 |
| 738 // If the err is of type *ec2.Error, ec2ErrCode returns | 742 // If the err is of type *ec2.Error, ec2ErrCode returns |
| 739 // its code, otherwise it returns the empty string. | 743 // its code, otherwise it returns the empty string. |
| 740 func ec2ErrCode(err error) string { | 744 func ec2ErrCode(err error) string { |
| 741 ec2err, _ := err.(*ec2.Error) | 745 ec2err, _ := err.(*ec2.Error) |
| 742 if ec2err == nil { | 746 if ec2err == nil { |
| 743 return "" | 747 return "" |
| 744 } | 748 } |
| 745 return ec2err.Code | 749 return ec2err.Code |
| 746 } | 750 } |
| OLD | NEW |