@@ -36,6 +36,10 @@ func (p *ProvisionerAPI) ProvisioningInfo(args params.Entities) (params.Provisio
36
36
if err != nil {
37
37
return result , errors .Trace (err )
38
38
}
39
+ env , err := environs .GetEnviron (p .configGetter , environs .New )
40
+ if err != nil {
41
+ return result , errors .Annotate (err , "could not get environ" )
42
+ }
39
43
for i , entity := range args .Entities {
40
44
tag , err := names .ParseMachineTag (entity .Tag )
41
45
if err != nil {
@@ -44,20 +48,20 @@ func (p *ProvisionerAPI) ProvisioningInfo(args params.Entities) (params.Provisio
44
48
}
45
49
machine , err := p .getMachine (canAccess , tag )
46
50
if err == nil {
47
- result .Results [i ].Result , err = p .getProvisioningInfo (machine )
51
+ result .Results [i ].Result , err = p .getProvisioningInfo (machine , env )
48
52
}
49
53
result .Results [i ].Error = common .ServerError (err )
50
54
}
51
55
return result , nil
52
56
}
53
57
54
- func (p * ProvisionerAPI ) getProvisioningInfo (m * state.Machine ) (* params.ProvisioningInfo , error ) {
58
+ func (p * ProvisionerAPI ) getProvisioningInfo (m * state.Machine , env environs. Environ ) (* params.ProvisioningInfo , error ) {
55
59
cons , err := m .Constraints ()
56
60
if err != nil {
57
61
return nil , errors .Trace (err )
58
62
}
59
63
60
- volumes , err := p .machineVolumeParams (m )
64
+ volumes , volumeAttachments , err := p .machineVolumeParams (m , env )
61
65
if err != nil {
62
66
return nil , errors .Trace (err )
63
67
}
@@ -81,97 +85,117 @@ func (p *ProvisionerAPI) getProvisioningInfo(m *state.Machine) (*params.Provisio
81
85
if err != nil {
82
86
return nil , errors .Annotate (err , "cannot determine machine endpoint bindings" )
83
87
}
84
- imageMetadata , err := p .availableImageMetadata (m )
88
+
89
+ imageMetadata , err := p .availableImageMetadata (m , env )
85
90
if err != nil {
86
91
return nil , errors .Annotate (err , "cannot get available image metadata" )
87
92
}
93
+
88
94
controllerCfg , err := p .st .ControllerConfig ()
89
95
if err != nil {
90
96
return nil , errors .Annotate (err , "cannot get controller configuration" )
91
97
}
92
98
93
99
return & params.ProvisioningInfo {
94
- Constraints : cons ,
95
- Series : m .Series (),
96
- Placement : m .Placement (),
97
- Jobs : jobs ,
98
- Volumes : volumes ,
99
- Tags : tags ,
100
- SubnetsToZones : subnetsToZones ,
101
- EndpointBindings : endpointBindings ,
102
- ImageMetadata : imageMetadata ,
103
- ControllerConfig : controllerCfg ,
100
+ Constraints : cons ,
101
+ Series : m .Series (),
102
+ Placement : m .Placement (),
103
+ Jobs : jobs ,
104
+ Volumes : volumes ,
105
+ VolumeAttachments : volumeAttachments ,
106
+ Tags : tags ,
107
+ SubnetsToZones : subnetsToZones ,
108
+ EndpointBindings : endpointBindings ,
109
+ ImageMetadata : imageMetadata ,
110
+ ControllerConfig : controllerCfg ,
104
111
}, nil
105
112
}
106
113
107
114
// machineVolumeParams retrieves VolumeParams for the volumes that should be
108
115
// provisioned with, and attached to, the machine. The client should ignore
109
116
// parameters that it does not know how to handle.
110
- func (p * ProvisionerAPI ) machineVolumeParams (m * state.Machine ) ([]params.VolumeParams , error ) {
117
+ func (p * ProvisionerAPI ) machineVolumeParams (
118
+ m * state.Machine ,
119
+ env environs.Environ ,
120
+ ) ([]params.VolumeParams , []params.VolumeAttachmentParams , error ) {
111
121
volumeAttachments , err := m .VolumeAttachments ()
112
122
if err != nil {
113
- return nil , errors .Trace (err )
123
+ return nil , nil , errors .Trace (err )
114
124
}
115
125
if len (volumeAttachments ) == 0 {
116
- return nil , nil
126
+ return nil , nil , nil
117
127
}
118
128
modelConfig , err := p .st .ModelConfig ()
119
129
if err != nil {
120
- return nil , errors .Trace (err )
130
+ return nil , nil , errors .Trace (err )
121
131
}
122
132
controllerCfg , err := p .st .ControllerConfig ()
123
133
if err != nil {
124
- return nil , errors .Trace (err )
134
+ return nil , nil , errors .Trace (err )
125
135
}
126
136
allVolumeParams := make ([]params.VolumeParams , 0 , len (volumeAttachments ))
137
+ var allVolumeAttachmentParams []params.VolumeAttachmentParams
127
138
for _ , volumeAttachment := range volumeAttachments {
128
139
volumeTag := volumeAttachment .Volume ()
129
140
volume , err := p .st .Volume (volumeTag )
130
141
if err != nil {
131
- return nil , errors .Annotatef (err , "getting volume %q" , volumeTag .Id ())
142
+ return nil , nil , errors .Annotatef (err , "getting volume %q" , volumeTag .Id ())
132
143
}
133
144
storageInstance , err := storagecommon .MaybeAssignedStorageInstance (
134
145
volume .StorageInstance , p .st .StorageInstance ,
135
146
)
136
147
if err != nil {
137
- return nil , errors .Annotatef (err , "getting volume %q storage instance" , volumeTag .Id ())
148
+ return nil , nil , errors .Annotatef (err , "getting volume %q storage instance" , volumeTag .Id ())
138
149
}
139
150
volumeParams , err := storagecommon .VolumeParams (
140
151
volume , storageInstance , modelConfig .UUID (), controllerCfg .ControllerUUID (),
141
152
modelConfig , p .storagePoolManager , p .storageProviderRegistry ,
142
153
)
143
154
if err != nil {
144
- return nil , errors .Annotatef (err , "getting volume %q parameters" , volumeTag .Id ())
145
- }
146
- provider , err := p .storageProviderRegistry .StorageProvider (storage .ProviderType (volumeParams .Provider ))
147
- if err != nil {
148
- return nil , errors .Annotate (err , "getting storage provider" )
155
+ return nil , nil , errors .Annotatef (err , "getting volume %q parameters" , volumeTag .Id ())
149
156
}
150
- if provider .Dynamic () {
151
- // Leave dynamic storage to the storage provisioner.
157
+ if _ , err := env .StorageProvider (storage .ProviderType (volumeParams .Provider )); errors .IsNotFound (err ) {
158
+ // This storage type is not managed by the environ
159
+ // provider, so ignore it. It'll be managed by one
160
+ // of the storage provisioners.
152
161
continue
162
+ } else if err != nil {
163
+ return nil , nil , errors .Annotate (err , "getting storage provider" )
153
164
}
154
- volumeAttachmentParams , ok := volumeAttachment .Params ()
155
- if ! ok {
156
- // Attachment is already provisioned; this is an insane
157
- // state, so we should not proceed with the volume.
158
- return nil , errors .Errorf (
159
- "volume %s already attached to machine %s" ,
160
- volumeTag .Id (), m .Id (),
161
- )
165
+
166
+ var volumeProvisioned bool
167
+ volumeInfo , err := volume .Info ()
168
+ if err == nil {
169
+ volumeProvisioned = true
170
+ } else if ! errors .IsNotProvisioned (err ) {
171
+ return nil , nil , errors .Annotate (err , "getting volume info" )
162
172
}
163
- // Not provisioned yet, so ask the cloud provisioner do it.
164
- volumeParams .Attachment = & params.VolumeAttachmentParams {
173
+ stateVolumeAttachmentParams , volumeDetached := volumeAttachment .Params ()
174
+ if ! volumeDetached {
175
+ // Volume is already attached to the machine, so
176
+ // there's nothing more to do for it.
177
+ continue
178
+ }
179
+ volumeAttachmentParams := params.VolumeAttachmentParams {
165
180
volumeTag .String (),
166
181
m .Tag ().String (),
167
- "" , // we're creating the volume, so it has no volume ID.
182
+ volumeInfo . VolumeId ,
168
183
"" , // we're creating the machine, so it has no instance ID.
169
184
volumeParams .Provider ,
170
- volumeAttachmentParams .ReadOnly ,
185
+ stateVolumeAttachmentParams .ReadOnly ,
186
+ }
187
+ if volumeProvisioned {
188
+ // Volume is already provisioned, so we just need to attach it.
189
+ allVolumeAttachmentParams = append (
190
+ allVolumeAttachmentParams , volumeAttachmentParams ,
191
+ )
192
+ } else {
193
+ // Not provisioned yet, so ask the cloud provisioner do it.
194
+ volumeParams .Attachment = & volumeAttachmentParams
195
+ allVolumeParams = append (allVolumeParams , volumeParams )
171
196
}
172
- allVolumeParams = append (allVolumeParams , volumeParams )
173
197
}
174
- return allVolumeParams , nil
198
+ return allVolumeParams , allVolumeAttachmentParams , nil
175
199
}
176
200
177
201
// machineTags returns machine-specific tags to set on the instance.
@@ -354,8 +378,8 @@ func (p *ProvisionerAPI) allSpaceNamesToProviderIds() (map[string]string, error)
354
378
355
379
// availableImageMetadata returns all image metadata available to this machine
356
380
// or an error fetching them.
357
- func (p * ProvisionerAPI ) availableImageMetadata (m * state.Machine ) ([]params.CloudImageMetadata , error ) {
358
- imageConstraint , env , err := p .constructImageConstraint (m )
381
+ func (p * ProvisionerAPI ) availableImageMetadata (m * state.Machine , env environs. Environ ) ([]params.CloudImageMetadata , error ) {
382
+ imageConstraint , err := p .constructImageConstraint (m , env )
359
383
if err != nil {
360
384
return nil , errors .Annotate (err , "could not construct image constraint" )
361
385
}
@@ -371,52 +395,34 @@ func (p *ProvisionerAPI) availableImageMetadata(m *state.Machine) ([]params.Clou
371
395
}
372
396
373
397
// constructImageConstraint returns model-specific criteria used to look for image metadata.
374
- func (p * ProvisionerAPI ) constructImageConstraint (m * state.Machine ) (* imagemetadata.ImageConstraint , environs.Environ , error ) {
375
- // If we can determine current region,
376
- // we want only metadata specific to this region.
377
- cloud , env , err := p .obtainEnvCloudConfig ()
378
- if err != nil {
379
- return nil , nil , errors .Trace (err )
380
- }
381
-
398
+ func (p * ProvisionerAPI ) constructImageConstraint (m * state.Machine , env environs.Environ ) (* imagemetadata.ImageConstraint , error ) {
382
399
lookup := simplestreams.LookupParams {
383
400
Series : []string {m .Series ()},
384
401
Stream : env .Config ().ImageStream (),
385
402
}
386
403
387
404
mcons , err := m .Constraints ()
388
405
if err != nil {
389
- return nil , nil , errors .Annotatef (err , "cannot get machine constraints for machine %v" , m .MachineTag ().Id ())
406
+ return nil , errors .Annotatef (err , "cannot get machine constraints for machine %v" , m .MachineTag ().Id ())
390
407
}
391
408
392
409
if mcons .Arch != nil {
393
410
lookup .Arches = []string {* mcons .Arch }
394
411
}
395
- if cloud != nil {
396
- lookup .CloudSpec = * cloud
397
- }
398
-
399
- return imagemetadata .NewImageConstraint (lookup ), env , nil
400
- }
401
-
402
- // obtainEnvCloudConfig returns environment specific cloud information
403
- // to be used in search for compatible images and their metadata.
404
- func (p * ProvisionerAPI ) obtainEnvCloudConfig () (* simplestreams.CloudSpec , environs.Environ , error ) {
405
- env , err := environs .GetEnviron (p .configGetter , environs .New )
406
- if err != nil {
407
- return nil , nil , errors .Annotate (err , "could not get model" )
408
- }
409
412
410
- if inst , ok := env .(simplestreams.HasRegion ); ok {
411
- cloud , err := inst .Region ()
413
+ if hasRegion , ok := env .(simplestreams.HasRegion ); ok {
414
+ // We can determine current region; we want only
415
+ // metadata specific to this region.
416
+ spec , err := hasRegion .Region ()
412
417
if err != nil {
413
418
// can't really find images if we cannot determine cloud region
414
419
// TODO (anastasiamac 2015-12-03) or can we?
415
- return nil , nil , errors .Annotate (err , "getting provider region information (cloud spec)" )
420
+ return nil , errors .Annotate (err , "getting provider region information (cloud spec)" )
416
421
}
417
- return & cloud , env , nil
422
+ lookup . CloudSpec = spec
418
423
}
419
- return nil , env , nil
424
+
425
+ return imagemetadata .NewImageConstraint (lookup ), nil
420
426
}
421
427
422
428
// findImageMetadata returns all image metadata or an error fetching them.
0 commit comments