Put the correct AzureTags type in StateBag (#10014)

Azure expects the tags format to use a pointer to the string for the map value.
The configuration from the builder is not a pointer so when storing in the state bag for
reference in later execution we convert it when creating the StateBag.

Fixes #10012 and #10013.

* Use the MapToAzureTags helper and error check in resource group creation

* Added test case for tag values not using a pointer

* test/azure/arm: Add test to verify tags stored in state

* test/azure/arm: Add azure_tags to existing acceptance test for Linux

Test Before Fix
```
--- FAIL: TestBuilderAcc_ManagedDisk_Linux (1.81s)
panic: interface conversion: interface {} is map[string]string, not map[string]*string [recovered]
        panic: interface conversion: interface {} is map[string]string, not map[string]*string
FAIL    github.com/hashicorp/packer/builder/azure/arm   1.822s

```

Test After Fix
```
2020/09/29 17:23:03 ui: ==> test: Resource group has been deleted.
--- PASS: TestBuilderAcc_ManagedDisk_Linux (517.41s)
    PASS
    ok      github.com/hashicorp/packer/builder/azure/arm   517.426s
```

Co-authored-by: Wilken Rivera <dev@wilkenrivera.com>
This commit is contained in:
Braunson 2020-09-30 09:55:46 -04:00 committed by GitHub
parent 2f4490fd73
commit b2047bd938
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 76 additions and 5 deletions

View File

@ -390,7 +390,7 @@ func (b *Builder) getBlobAccount(ctx context.Context, client *AzureClient, resou
func (b *Builder) configureStateBag(stateBag multistep.StateBag) { func (b *Builder) configureStateBag(stateBag multistep.StateBag) {
stateBag.Put(constants.AuthorizedKey, b.config.sshAuthorizedKey) stateBag.Put(constants.AuthorizedKey, b.config.sshAuthorizedKey)
stateBag.Put(constants.ArmTags, b.config.AzureTags) stateBag.Put(constants.ArmTags, packerAzureCommon.MapToAzureTags(b.config.AzureTags))
stateBag.Put(constants.ArmComputeName, b.config.tmpComputeName) stateBag.Put(constants.ArmComputeName, b.config.tmpComputeName)
stateBag.Put(constants.ArmDeploymentName, b.config.tmpDeploymentName) stateBag.Put(constants.ArmDeploymentName, b.config.tmpDeploymentName)

View File

@ -223,7 +223,11 @@ const testBuilderAccManagedDiskLinux = `
"image_sku": "16.04-LTS", "image_sku": "16.04-LTS",
"location": "South Central US", "location": "South Central US",
"vm_size": "Standard_DS2_v2" "vm_size": "Standard_DS2_v2",
"azure_tags": {
"env": "testing",
"builder": "packer"
}
}] }]
} }
` `

View File

@ -33,3 +33,35 @@ func TestStateBagShouldBePopulatedExpectedValues(t *testing.T) {
} }
} }
} }
func TestStateBagShouldPoluateExpectedTags(t *testing.T) {
var testSubject Builder
expectedTags := map[string]string{
"env": "test",
"builder": "packer",
}
armConfig := getArmBuilderConfiguration()
armConfig["azure_tags"] = expectedTags
_, _, err := testSubject.Prepare(armConfig, getPackerConfiguration())
if err != nil {
t.Fatalf("failed to prepare: %s", err)
}
tags, ok := testSubject.stateBag.Get(constants.ArmTags).(map[string]*string)
if !ok {
t.Errorf("Expected the builder's state bag to contain tags of type %T, but didn't.", testSubject.config.AzureTags)
}
if len(tags) != len(expectedTags) {
t.Errorf("expect tags from state to be the same length as tags from config")
}
for k, v := range tags {
if expectedTags[k] != *v {
t.Errorf("expect tag value of %s to be %s, but got %s", k, expectedTags[k], *v)
}
}
}

View File

@ -2072,8 +2072,8 @@ func TestConfig_PrepareProvidedWinRMPassword(t *testing.T) {
} }
} }
func getArmBuilderConfiguration() map[string]string { func getArmBuilderConfiguration() map[string]interface{} {
m := make(map[string]string) m := make(map[string]interface{})
for _, v := range requiredConfigValues { for _, v := range requiredConfigValues {
m[v] = "ignored00" m[v] = "ignored00"
} }

View File

@ -61,7 +61,13 @@ func (s *StepCreateResourceGroup) Run(ctx context.Context, state multistep.State
var resourceGroupName = state.Get(constants.ArmResourceGroupName).(string) var resourceGroupName = state.Get(constants.ArmResourceGroupName).(string)
var location = state.Get(constants.ArmLocation).(string) var location = state.Get(constants.ArmLocation).(string)
var tags = state.Get(constants.ArmTags).(map[string]*string) tags, ok := state.Get(constants.ArmTags).(map[string]*string)
if !ok {
err := fmt.Errorf("failed to extract tags from state bag")
state.Put(constants.Error, err)
s.error(err)
return multistep.ActionHalt
}
exists, err := s.exists(ctx, resourceGroupName) exists, err := s.exists(ctx, resourceGroupName)
if err != nil { if err != nil {

View File

@ -220,3 +220,32 @@ func createTestExistingStateBagStepCreateResourceGroup() multistep.StateBag {
stateBag.Put(constants.ArmTags, tags) stateBag.Put(constants.ArmTags, tags)
return stateBag return stateBag
} }
func TestStepCreateResourceGroupShouldFailIfTagsFailCast(t *testing.T) {
stateBag := new(multistep.BasicStateBag)
stateBag.Put(constants.ArmLocation, "Unit Test: Location")
stateBag.Put(constants.ArmResourceGroupName, "Unit Test: ResourceGroupName")
stateBag.Put(constants.ArmIsExistingResourceGroup, true)
value := "Unit Test: Tags"
tags := map[string]string{
"tag01": value,
}
stateBag.Put(constants.ArmTags, tags)
var testSubject = &StepCreateResourceGroup{
create: func(context.Context, string, string, map[string]*string) error { return nil },
say: func(message string) {},
error: func(e error) {},
exists: func(context.Context, string) (bool, error) { return false, nil },
}
var result = testSubject.Run(context.Background(), stateBag)
if result != multistep.ActionHalt {
t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result)
}
if _, ok := stateBag.GetOk(constants.Error); ok == false {
t.Fatalf("Expected the step to set stateBag['%s'], but it was not.", constants.Error)
}
}