Skip to content
This repository was archived by the owner on Jan 21, 2020. It is now read-only.

Commit fcc0579

Browse files
kaufersDavid Chung
authored andcommitted
Handle LogicalID for Softlayer instances (#548)
The current LogicalID processing in the terraform instance provider has two issues: - The LogicalID tag is only added to the tags if the tags object type is map but, for Softlayer, the tags object type is a list - Softlayer only supports lower-case chars in tags so all tag checks for "LogicalID" must support case-insensitive key checks This also moves the logic to make the Softlayer tags all lower case to one common place; allowing the code to process tags generically and then we manipulate at the end. Closes #546 Signed-off-by: Steven Kaufer <[email protected]>
1 parent 928f3e3 commit fcc0579

File tree

2 files changed

+67
-31
lines changed

2 files changed

+67
-31
lines changed

examples/instance/terraform/plugin.go

Lines changed: 48 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -362,25 +362,28 @@ func (p *plugin) Provision(spec instance.Spec) (*instance.ID, error) {
362362
return nil, fmt.Errorf("no-vm-instance-in-spec")
363363
}
364364

365-
// set the tags.
366-
// add a name
365+
// Add the name to the tags if it does not exist, issue case-insensitive
366+
// check for the "name" key
367367
if spec.Tags != nil {
368-
switch vmType {
369-
case VMSoftLayer:
370-
// Set the "name" tag to be lowercase to meet platform requirements
371-
if _, has := spec.Tags["name"]; !has {
372-
spec.Tags["name"] = string(id)
373-
}
374-
default:
375-
// Set the first character of the "Name" tag to be uppercase to meet platform requirements
376-
if _, has := spec.Tags["Name"]; !has {
377-
spec.Tags["Name"] = string(id)
368+
match := false
369+
for key := range spec.Tags {
370+
if strings.ToLower(key) == "name" {
371+
match = true
372+
break
378373
}
379374
}
375+
if !match {
376+
spec.Tags["Name"] = string(id)
377+
}
378+
}
379+
// Use tag to store the logical id
380+
if spec.LogicalID != nil {
381+
spec.Tags["LogicalID"] = string(*spec.LogicalID)
380382
}
381383

382384
p.optionalProcessHostname(vmType, TResourceName(name), properties)
383385

386+
// Merge any user-defined tags and convert to platform specific tag type
384387
switch vmType {
385388
case VMAmazon, VMAzure, VMDigitalOcean, VMGoogleCloud:
386389
if t, exists := properties["tags"]; !exists {
@@ -402,12 +405,6 @@ func (p *plugin) Provision(spec instance.Spec) (*instance.ID, error) {
402405
}
403406
}
404407

405-
// Use tag to store the logical id
406-
if spec.LogicalID != nil {
407-
if m, ok := properties["tags"].(map[string]interface{}); ok {
408-
m["LogicalID"] = string(*spec.LogicalID)
409-
}
410-
}
411408
switch vmType {
412409
case VMAmazon:
413410
if p, exists := properties["private_ip"]; exists {
@@ -444,6 +441,16 @@ func (p *plugin) Provision(spec instance.Spec) (*instance.ID, error) {
444441
addUserData(properties, "metadata_startup_script", spec.Init)
445442
}
446443

444+
// On Softlayer the tags must be lowercase
445+
switch vmType {
446+
case VMSoftLayer:
447+
tagsLower := []string{}
448+
for _, val := range properties["tags"].([]string) {
449+
tagsLower = append(tagsLower, strings.ToLower(val))
450+
}
451+
properties["tags"] = tagsLower
452+
}
453+
447454
// Write out each resource again with the instance name
448455
for resourceType, resourceObj := range tf.Resource {
449456
vmList := mapset.NewSetFromSlice(VMTypes)
@@ -656,19 +663,29 @@ func terraformTags(m TResourceProperties, key string) map[string]string {
656663
}
657664
return tags
658665
}
659-
func terraformLogicalID(v interface{}) *instance.LogicalID {
660-
m, ok := v.(map[string]interface{})
661-
if !ok {
662-
return nil
663-
}
664-
tags, ok := m["tags"].(map[string]interface{})
665-
if !ok {
666-
return nil
667-
}
668-
v, exists := tags["LogicalID"]
669-
if exists {
670-
id := instance.LogicalID(fmt.Sprintf("%v", v))
671-
return &id
666+
667+
// terraformLogicalID parses the LogicalID (case insensitive key check) from
668+
// either the map of tags or the list of tags
669+
func terraformLogicalID(props TResourceProperties) *instance.LogicalID {
670+
if propsTag, ok := props["tags"]; ok {
671+
if tagsMap, ok := propsTag.(map[string]interface{}); ok {
672+
for key, val := range tagsMap {
673+
if strings.ToLower(key) == "logicalid" {
674+
id := instance.LogicalID(fmt.Sprintf("%v", val))
675+
return &id
676+
}
677+
}
678+
} else if tagsList, ok := propsTag.([]interface{}); ok {
679+
for _, tag := range tagsList {
680+
if tagString, ok := tag.(string); ok {
681+
if strings.HasPrefix(strings.ToLower(tagString), "logicalid:") {
682+
logicalID := strings.SplitN(strings.ToLower(tagString), ":", 2)[1]
683+
id := instance.LogicalID(fmt.Sprintf("%v", logicalID))
684+
return &id
685+
}
686+
}
687+
}
688+
}
672689
}
673690
return nil
674691
}

examples/instance/terraform/plugin_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,14 +182,17 @@ func run(t *testing.T, resourceType, properties string) {
182182
require.NoError(t, err)
183183

184184
// Instance with tags that will not be updated
185+
logicalID1 := instance.LogicalID("logical.id-1")
185186
instanceSpec1 := instance.Spec{
186187
Properties: config,
187188
Tags: map[string]string{
188189
"label1": "value1",
189190
"label2": "value2",
191+
"LABEL3": "VALUE3",
190192
},
191193
Init: "",
192194
Attachments: []instance.Attachment{},
195+
LogicalID: &logicalID1,
193196
}
194197
id1, err := terraform.Provision(instanceSpec1)
195198
require.NoError(t, err)
@@ -198,6 +201,7 @@ func run(t *testing.T, resourceType, properties string) {
198201
require.NoError(t, err)
199202

200203
// Instance with tags that will be updated
204+
logicalID2 := instance.LogicalID("logical:id-2")
201205
instanceSpec2 := instance.Spec{
202206
Properties: config,
203207
Tags: map[string]string{
@@ -211,6 +215,7 @@ func run(t *testing.T, resourceType, properties string) {
211215
Type: "ebs",
212216
},
213217
},
218+
LogicalID: &logicalID2,
214219
}
215220
id2, err := terraform.Provision(instanceSpec2)
216221
require.NoError(t, err)
@@ -250,6 +255,7 @@ func run(t *testing.T, resourceType, properties string) {
250255
"label1:value1",
251256
"label2:value2",
252257
"name:" + string(*id2),
258+
"logicalid:logical:id-2",
253259
}), conv(props["tags"].([]interface{})))
254260
require.Equal(t, expectedUserData2, props["user_metadata"])
255261

@@ -271,6 +277,7 @@ func run(t *testing.T, resourceType, properties string) {
271277
"label1": "value1",
272278
"label2": "value2",
273279
"Name": string(*id2),
280+
"LogicalID": "logical:id-2",
274281
}, props["tags"])
275282
require.Equal(t, base64.StdEncoding.EncodeToString([]byte(expectedUserData2)), props["user_data"])
276283

@@ -305,8 +312,11 @@ func run(t *testing.T, resourceType, properties string) {
305312
"terraform_demo_swarm_mgr_sl": "",
306313
"label1": "value1",
307314
"label2": "value2",
315+
"label3": "value3",
308316
"name": string(*id1),
317+
"logicalid": "logical.id-1",
309318
},
319+
LogicalID: &logicalID1,
310320
}
311321
inst2 = instance.Description{
312322
ID: *id2,
@@ -315,7 +325,9 @@ func run(t *testing.T, resourceType, properties string) {
315325
"label1": "value1",
316326
"label2": "value2",
317327
"name": string(*id2),
328+
"logicalid": "logical:id-2",
318329
},
330+
LogicalID: &logicalID2,
319331
}
320332
case VMAmazon:
321333
inst1 = instance.Description{
@@ -324,8 +336,11 @@ func run(t *testing.T, resourceType, properties string) {
324336
"InstancePlugin": "terraform",
325337
"label1": "value1",
326338
"label2": "value2",
339+
"LABEL3": "VALUE3",
327340
"Name": string(*id1),
341+
"LogicalID": "logical.id-1",
328342
},
343+
LogicalID: &logicalID1,
329344
}
330345
inst2 = instance.Description{
331346
ID: *id2,
@@ -334,7 +349,9 @@ func run(t *testing.T, resourceType, properties string) {
334349
"label1": "value1",
335350
"label2": "value2",
336351
"Name": string(*id2),
352+
"LogicalID": "logical:id-2",
337353
},
354+
LogicalID: &logicalID2,
338355
}
339356
}
340357

@@ -370,6 +387,7 @@ func run(t *testing.T, resourceType, properties string) {
370387
"label2:value2",
371388
"label3:value3",
372389
"name:" + string(*id2),
390+
"logicalid:logical:id-2",
373391
}), conv(props["tags"].([]interface{})))
374392
case VMAmazon:
375393
require.Equal(t, map[string]interface{}{
@@ -378,6 +396,7 @@ func run(t *testing.T, resourceType, properties string) {
378396
"label2": "value2",
379397
"label3": "value3",
380398
"Name": string(*id2),
399+
"LogicalID": "logical:id-2",
381400
}, props["tags"])
382401
}
383402

0 commit comments

Comments
 (0)