1
1
package ddcloud
2
2
3
3
import (
4
+ "fmt"
5
+ "github.com/DimensionDataResearch/dd-cloud-compute-terraform/retry"
6
+ "github.com/DimensionDataResearch/go-dd-cloud-compute/compute"
4
7
"github.com/hashicorp/terraform/helper/schema"
5
8
"github.com/pkg/errors"
6
9
"log"
@@ -14,6 +17,7 @@ const (
14
17
resourceKeyAddressPrefixSize = "prefix_size"
15
18
resourceKeyAddressNetworkDomainID = "networkdomain"
16
19
resourceKeyAddressListID = "addresslist_id"
20
+ resourceKeyAddressAddressListName = "addresslist_name"
17
21
)
18
22
19
23
func resourceAddress () * schema.Resource {
@@ -31,11 +35,11 @@ func resourceAddress() *schema.Resource {
31
35
Required : true ,
32
36
Description : "The Id of the network domain in which the address applies" ,
33
37
},
34
- resourceKeyAddressListID : & schema.Schema {
38
+ resourceKeyAddressAddressListName : & schema.Schema {
35
39
Type : schema .TypeString ,
36
40
ForceNew : true ,
37
41
Required : true ,
38
- Description : "The Id of the address list" ,
42
+ Description : "The Name of the address list" ,
39
43
},
40
44
resourceKeyAddressBegin : & schema.Schema {
41
45
Type : schema .TypeString ,
@@ -64,9 +68,17 @@ func resourceAddress() *schema.Resource {
64
68
// Check if an address list resource exists.
65
69
func resourceAddressExists (data * schema.ResourceData , provider interface {}) (bool , error ) {
66
70
log .Printf ("resourceAddressExists" )
67
- addressListId := data .Get (resourceKeyAddressListID ).(string )
68
-
69
71
client := provider .(* providerState ).Client ()
72
+ networkDomainId := data .Get (resourceKeyAddressNetworkDomainID ).(string )
73
+ addressListName := data .Get (resourceKeyAddressAddressListName ).(string )
74
+ addrList , _ := client .GetIPAddressListByName (addressListName , networkDomainId )
75
+
76
+ var addressListId string
77
+ if addrList == nil {
78
+ return false , nil
79
+ } else {
80
+ addressListId = addrList .ID
81
+ }
70
82
71
83
begin , okBegin := data .GetOk (resourceKeyAddressBegin )
72
84
network , okNetwork := data .GetOk (resourceKeyAddressNetwork )
@@ -92,7 +104,19 @@ func resourceAddressCreate(data *schema.ResourceData, provider interface{}) erro
92
104
var network string
93
105
var prefixSize int
94
106
95
- addressListId := data .Get (resourceKeyAddressListID ).(string )
107
+ providerState := provider .(* providerState )
108
+ client := providerState .Client ()
109
+
110
+ addressListName := data .Get (resourceKeyAddressAddressListName ).(string )
111
+ networkDomainId := data .Get (resourceKeyAddressNetworkDomainID ).(string )
112
+ addrList , err := client .GetIPAddressListByName (addressListName , networkDomainId )
113
+
114
+ var addressListId string
115
+ if err != nil {
116
+ return err
117
+ } else {
118
+ addressListId = addrList .ID
119
+ }
96
120
97
121
valBegin , beginOk := data .GetOk (resourceKeyAddressBegin )
98
122
if beginOk {
@@ -124,8 +148,26 @@ func resourceAddressCreate(data *schema.ResourceData, provider interface{}) erro
124
148
}
125
149
}
126
150
127
- client := provider .(* providerState ).Client ()
128
- _ , err := client .AddAddress (addressListId , begin , end , network , prefixSize )
151
+ operationDescription := fmt .Sprintf ("Add Address to FW Address List'" )
152
+
153
+ err = providerState .RetryAction (operationDescription , func (context retry.Context ) {
154
+ // CloudControl has issues if more than one asynchronous operation is initated at a time (returns UNEXPECTED_ERROR).
155
+ asyncLock := providerState .AcquireAsyncOperationLock ("Create Address begin:'%s' end:%s network:%s prefix:%d" ,
156
+ valBegin , valEnd , valNetwork , valPrefix )
157
+ defer asyncLock .Release ()
158
+
159
+ _ , deployError := client .AddAddress (addressListId , begin , end , network , prefixSize )
160
+
161
+ if deployError != nil {
162
+ if compute .IsResourceBusyError (deployError ) {
163
+ context .Retry ()
164
+ } else {
165
+ context .Fail (deployError )
166
+ }
167
+ }
168
+
169
+ asyncLock .Release ()
170
+ })
129
171
130
172
if err != nil {
131
173
return err
@@ -147,12 +189,22 @@ func resourceAddressCreate(data *schema.ResourceData, provider interface{}) erro
147
189
func resourceAddressRead (data * schema.ResourceData , provider interface {}) error {
148
190
log .Printf ("resourceAddressRead" )
149
191
150
- addressListId := data .Get (resourceKeyAddressListID ).(string )
151
192
begin , _ := data .GetOk (resourceKeyAddressBegin )
152
193
network , _ := data .GetOk (resourceKeyAddressNetwork )
153
194
154
195
client := provider .(* providerState ).Client ()
155
196
197
+ networkDomainId := data .Get (resourceKeyAddressNetworkDomainID ).(string )
198
+ addressListName := data .Get (resourceKeyAddressAddressListName ).(string )
199
+ addrList , err := client .GetIPAddressListByName (addressListName , networkDomainId )
200
+
201
+ var addressListId string
202
+ if err != nil {
203
+ return err
204
+ } else {
205
+ addressListId = addrList .ID
206
+ }
207
+
156
208
// Check if address exists in cloud
157
209
addr , addrOk := client .GetAddressOk (addressListId , begin .(string ), network .(string ))
158
210
if ! addrOk {
@@ -192,7 +244,19 @@ func resourceAddressUpdate(data *schema.ResourceData, provider interface{}) erro
192
244
// Enable partial state mode
193
245
// data.Partial(true)
194
246
195
- addressListId := data .Get (resourceKeyAddressListID ).(string )
247
+ providerState := provider .(* providerState )
248
+ client := providerState .Client ()
249
+
250
+ networkDomainId := data .Get (resourceKeyAddressNetworkDomainID ).(string )
251
+ addressListName := data .Get (resourceKeyAddressAddressListName ).(string )
252
+ addrList , err := client .GetIPAddressListByName (addressListName , networkDomainId )
253
+
254
+ var addressListId string
255
+ if err != nil {
256
+ return err
257
+ } else {
258
+ addressListId = addrList .ID
259
+ }
196
260
197
261
valBegin , beginOk := data .GetOk (resourceKeyAddressBegin )
198
262
if beginOk {
@@ -214,8 +278,6 @@ func resourceAddressUpdate(data *schema.ResourceData, provider interface{}) erro
214
278
prefixSize = valPrefix .(int )
215
279
}
216
280
217
- client := provider .(* providerState ).Client ()
218
-
219
281
oldBegin , _ := data .GetChange (resourceKeyAddressBegin )
220
282
oldNetwork , _ := data .GetChange (resourceKeyAddressNetwork )
221
283
@@ -227,33 +289,49 @@ func resourceAddressUpdate(data *schema.ResourceData, provider interface{}) erro
227
289
ipAddress = oldNetwork .(string )
228
290
}
229
291
230
- // Update step 1: Remove old address
231
- _ , errOld := client .DeleteAddress (addressListId , ipAddress )
232
- if errOld != nil {
233
- return errOld
234
- }
292
+ operationDescription := fmt .Sprintf ("Delete Address in FW Address List'" )
293
+
294
+ err = providerState .RetryAction (operationDescription , func (context retry.Context ) {
295
+ // CloudControl has issues if more than one asynchronous operation is initated at a time (returns UNEXPECTED_ERROR).
296
+ asyncLock := providerState .AcquireAsyncOperationLock ("Delete Address '%s'" , valBegin )
297
+ defer asyncLock .Release ()
298
+
299
+ // Update step 1: Remove old address
300
+ _ , deployErr := client .DeleteAddress (addressListId , ipAddress )
301
+ if deployErr != nil {
302
+ return
303
+ }
235
304
236
- // Update step 2: Add new address
237
- newAddress , err := client .AddAddress (addressListId , begin , end , network , prefixSize )
305
+ // Update step 2: Add new address
306
+ newAddress , deployErr := client .AddAddress (addressListId , begin , end , network , prefixSize )
307
+
308
+ if deployErr != nil {
309
+ return
310
+ }
311
+
312
+ log .Printf ("Updated address: %s" , newAddress .Begin )
313
+
314
+ // We succeeded, disable partial mode. This causes Terraform to save
315
+ // all fields again.
316
+ // data.Partial(false)
317
+
318
+ asyncLock .Release ()
319
+ })
238
320
239
321
if err != nil {
240
322
return err
241
323
}
242
324
243
- log .Printf ("Updated address: %s" , newAddress .Begin )
244
-
245
- // We succeeded, disable partial mode. This causes Terraform to save
246
- // all fields again.
247
- // data.Partial(false)
248
-
249
325
return resourceAddressRead (data , provider )
250
326
}
251
327
252
328
// Delete an address list resource.
253
329
func resourceAddressDelete (data * schema.ResourceData , provider interface {}) error {
254
330
log .Printf ("resourceAddressDelete" )
255
331
256
- addressListId := data .Get (resourceKeyAddressListID ).(string )
332
+ providerState := provider .(* providerState )
333
+ client := providerState .Client ()
334
+
257
335
begin := data .Get (resourceKeyAddressBegin ).(string )
258
336
network := data .Get (resourceKeyAddressNetwork ).(string )
259
337
@@ -264,8 +342,35 @@ func resourceAddressDelete(data *schema.ResourceData, provider interface{}) erro
264
342
ip = network
265
343
}
266
344
267
- client := provider .(* providerState ).Client ()
268
- _ , err := client .DeleteAddress (addressListId , ip )
345
+ networkDomainId := data .Get (resourceKeyAddressNetworkDomainID ).(string )
346
+ addressListName := data .Get (resourceKeyAddressAddressListName ).(string )
347
+ addrList , err := client .GetIPAddressListByName (addressListName , networkDomainId )
348
+
349
+ var addressListId string
350
+ if err != nil {
351
+ return err
352
+ } else {
353
+ addressListId = addrList .ID
354
+ }
355
+
356
+ operationDescription := fmt .Sprintf ("Delete Address in FW Address List'" )
357
+
358
+ err = providerState .RetryAction (operationDescription , func (context retry.Context ) {
359
+ // CloudControl has issues if more than one asynchronous operation is initated at a time (returns UNEXPECTED_ERROR).
360
+ asyncLock := providerState .AcquireAsyncOperationLock ("Delete Address '%s'" , begin )
361
+ defer asyncLock .Release ()
362
+ _ , deployError := client .DeleteAddress (addressListId , ip )
363
+
364
+ if deployError != nil {
365
+ if compute .IsResourceBusyError (deployError ) {
366
+ context .Retry ()
367
+ } else {
368
+ context .Fail (deployError )
369
+ }
370
+ }
371
+
372
+ asyncLock .Release ()
373
+ })
269
374
270
375
if err != nil {
271
376
return err
0 commit comments