Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(3)

Side by Side Diff: environs/ec2/ec2.go

Issue 6416055: environs: split out config validation
Patch Set: environs: split out config validation Created 5 years, 5 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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 }
OLDNEW
« environs/ec2/config.go ('K') | « environs/ec2/config_test.go ('k') | environs/interface.go » ('j') | no next file with comments »

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld 204d58d