Issue #5045 - Add build_resource_group_name

* Created a new parameter for using existing resource groups
* Implemented logic to ensure temp_ and build_ can't both be used
* Implemented logic to ensure they can only be used in correct context
* Implemented tests for this logic
* Updated where required to ensure the process works
This commit is contained in:
Arjen Schwarz 2017-11-09 22:20:09 +11:00
parent 0377140c39
commit 0e706320ad
No known key found for this signature in database
GPG Key ID: FA9F4AB57F735243
7 changed files with 204 additions and 32 deletions

View File

@ -287,7 +287,16 @@ func (b *Builder) configureStateBag(stateBag multistep.StateBag) {
stateBag.Put(constants.ArmLocation, b.config.Location)
stateBag.Put(constants.ArmNicName, DefaultNicName)
stateBag.Put(constants.ArmPublicIPAddressName, DefaultPublicIPAddressName)
stateBag.Put(constants.ArmResourceGroupName, b.config.tmpResourceGroupName)
if b.config.TempResourceGroupName != "" && b.config.BuildResourceGroupName != "" {
stateBag.Put(constants.ArmDoubleResourceGroupNameSet, true)
}
if b.config.tmpResourceGroupName != "" {
stateBag.Put(constants.ArmResourceGroupName, b.config.tmpResourceGroupName)
stateBag.Put(constants.ArmIsExistingResourceGroup, false)
} else {
stateBag.Put(constants.ArmResourceGroupName, b.config.BuildResourceGroupName)
stateBag.Put(constants.ArmIsExistingResourceGroup, true)
}
stateBag.Put(constants.ArmStorageAccountName, b.config.StorageAccount)
stateBag.Put(constants.ArmIsManagedImage, b.config.isManagedImage())

View File

@ -83,6 +83,7 @@ type Config struct {
StorageAccount string `mapstructure:"storage_account"`
TempComputeName string `mapstructure:"temp_compute_name"`
TempResourceGroupName string `mapstructure:"temp_resource_group_name"`
BuildResourceGroupName string `mapstructure:"build_resource_group_name"`
storageAccountBlobEndpoint string
CloudEnvironmentName string `mapstructure:"cloud_environment_name"`
cloudEnvironment *azure.Environment
@ -129,7 +130,13 @@ type keyVaultCertificate struct {
}
func (c *Config) toVMID() string {
return fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Compute/virtualMachines/%s", c.SubscriptionID, c.tmpResourceGroupName, c.tmpComputeName)
var resourceGroupName string
if c.tmpResourceGroupName != "" {
resourceGroupName = c.tmpResourceGroupName
} else {
resourceGroupName = c.BuildResourceGroupName
}
return fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Compute/virtualMachines/%s", c.SubscriptionID, resourceGroupName, c.tmpComputeName)
}
func (c *Config) isManagedImage() bool {
@ -328,9 +335,10 @@ func setRuntimeValues(c *Config) {
c.tmpComputeName = c.TempComputeName
}
c.tmpDeploymentName = tempName.DeploymentName
if c.TempResourceGroupName == "" {
// Only set tmpResourceGroupName if no name has been specified
if c.TempResourceGroupName == "" && c.BuildResourceGroupName == "" {
c.tmpResourceGroupName = tempName.ResourceGroupName
} else {
} else if c.TempResourceGroupName != "" && c.BuildResourceGroupName == "" {
c.tmpResourceGroupName = c.TempResourceGroupName
}
c.tmpOSDiskName = tempName.OSDiskName

View File

@ -1,6 +1,7 @@
package arm
import (
"errors"
"fmt"
"github.com/Azure/azure-sdk-for-go/arm/resources/resources"
@ -51,32 +52,48 @@ func (s *StepCreateResourceGroup) doesResourceGroupExist(resourceGroupName strin
}
func (s *StepCreateResourceGroup) Run(state multistep.StateBag) multistep.StepAction {
s.say("Creating resource group ...")
var doubleResource, ok = state.GetOk(constants.ArmDoubleResourceGroupNameSet)
if ok && doubleResource.(bool) {
err := errors.New("You have filled in both temp_resource_group_name and build_resource_group_name. Please choose one.")
return processStepResult(err, s.error, state)
}
var resourceGroupName = state.Get(constants.ArmResourceGroupName).(string)
var location = state.Get(constants.ArmLocation).(string)
var tags = state.Get(constants.ArmTags).(*map[string]*string)
s.say(fmt.Sprintf(" -> ResourceGroupName : '%s'", resourceGroupName))
s.say(fmt.Sprintf(" -> Location : '%s'", location))
s.say(fmt.Sprintf(" -> Tags :"))
for k, v := range *tags {
s.say(fmt.Sprintf(" ->> %s : %s", k, *v))
}
exists, err := s.exists(resourceGroupName)
if err != nil {
s.say(s.client.LastError.Error())
return processStepResult(err, s.error, state)
}
state.Put(constants.ArmIsExistingResourceGroup, exists)
configThinksExists := state.Get(constants.ArmIsExistingResourceGroup).(bool)
if exists != configThinksExists {
if configThinksExists {
err = errors.New("The resource group you want to use does not exist yet. Please use temp_resource_group_name to create a temporary resource group.")
} else {
err = errors.New("A resource group with that name already exists. Please use build_resource_group_name to use an existing resource group.")
}
return processStepResult(err, s.error, state)
}
// If the resource group exists, we may not have permissions to update it so we don't.
if !exists {
s.say("Creating resource group ...")
s.say(fmt.Sprintf(" -> ResourceGroupName : '%s'", resourceGroupName))
s.say(fmt.Sprintf(" -> Location : '%s'", location))
s.say(fmt.Sprintf(" -> Tags :"))
for k, v := range *tags {
s.say(fmt.Sprintf(" ->> %s : %s", k, *v))
}
err = s.create(resourceGroupName, location, tags)
if err == nil {
state.Put(constants.ArmIsResourceGroupCreated, true)
}
} else {
// Mark the resource group as created to deal with later checks
s.say("Using existing resource group ...")
s.say(fmt.Sprintf(" -> ResourceGroupName : '%s'", resourceGroupName))
s.say(fmt.Sprintf(" -> Location : '%s'", location))
state.Put(constants.ArmIsResourceGroupCreated, true)
}

View File

@ -1,6 +1,7 @@
package arm
import (
"errors"
"fmt"
"testing"
@ -8,6 +9,33 @@ import (
"github.com/mitchellh/multistep"
)
func TestStepCreateResourceGroupShouldFailIfBothGroupNames(t *testing.T) {
stateBag := new(multistep.BasicStateBag)
stateBag.Put(constants.ArmDoubleResourceGroupNameSet, true)
value := "Unit Test: Tags"
tags := map[string]*string{
"tag01": &value,
}
stateBag.Put(constants.ArmTags, &tags)
var testSubject = &StepCreateResourceGroup{
create: func(string, string, *map[string]*string) error { return nil },
say: func(message string) {},
error: func(e error) {},
exists: func(string) (bool, error) { return false, nil },
}
var result = testSubject.Run(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)
}
}
func TestStepCreateResourceGroupShouldFailIfCreateFails(t *testing.T) {
var testSubject = &StepCreateResourceGroup{
create: func(string, string, *map[string]*string) error { return fmt.Errorf("!! Unit Test FAIL !!") },
@ -28,6 +56,26 @@ func TestStepCreateResourceGroupShouldFailIfCreateFails(t *testing.T) {
}
}
func TestStepCreateResourceGroupShouldFailIfExistsFails(t *testing.T) {
var testSubject = &StepCreateResourceGroup{
create: func(string, string, *map[string]*string) error { return nil },
say: func(message string) {},
error: func(e error) {},
exists: func(string) (bool, error) { return false, errors.New("FAIL") },
}
stateBag := createTestStateBagStepCreateResourceGroup()
var result = testSubject.Run(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)
}
}
func TestStepCreateResourceGroupShouldPassIfCreatePasses(t *testing.T) {
var testSubject = &StepCreateResourceGroup{
create: func(string, string, *map[string]*string) error { return nil },
@ -94,7 +142,7 @@ func TestStepCreateResourceGroupShouldTakeStepArgumentsFromStateBag(t *testing.T
}
}
func TestStepCreateResourceGroupMarkAsNonExistingIfDoesntExist(t *testing.T) {
func TestStepCreateResourceGroupMarkShouldFailIfTryingExistingButDoesntExist(t *testing.T) {
var testSubject = &StepCreateResourceGroup{
create: func(string, string, *map[string]*string) error { return fmt.Errorf("!! Unit Test FAIL !!") },
say: func(message string) {},
@ -102,18 +150,19 @@ func TestStepCreateResourceGroupMarkAsNonExistingIfDoesntExist(t *testing.T) {
exists: func(string) (bool, error) { return false, nil },
}
stateBag := createTestStateBagStepCreateResourceGroup()
stateBag := createTestExistingStateBagStepCreateResourceGroup()
if _, ok := stateBag.GetOk(constants.ArmIsExistingResourceGroup); ok == true {
t.Fatalf("Expected 'constants.ArmIsExistingResourceGroup' not to be set, but it was")
var result = testSubject.Run(stateBag)
if result != multistep.ActionHalt {
t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result)
}
testSubject.Run(stateBag)
if stateBag.Get(constants.ArmIsExistingResourceGroup).(bool) == true {
t.Fatalf("Expected 'constants.ArmIsExistingResourceGroup' to be set to false, but it wasn't.")
if _, ok := stateBag.GetOk(constants.Error); ok == false {
t.Fatalf("Expected the step to set stateBag['%s'], but it was not.", constants.Error)
}
}
func TestStepCreateResourceGroupMarkAsExistingIfExists(t *testing.T) {
func TestStepCreateResourceGroupMarkShouldFailIfTryingTempButExist(t *testing.T) {
var testSubject = &StepCreateResourceGroup{
create: func(string, string, *map[string]*string) error { return fmt.Errorf("!! Unit Test FAIL !!") },
say: func(message string) {},
@ -123,12 +172,13 @@ func TestStepCreateResourceGroupMarkAsExistingIfExists(t *testing.T) {
stateBag := createTestStateBagStepCreateResourceGroup()
if _, ok := stateBag.GetOk(constants.ArmIsExistingResourceGroup); ok == true {
t.Fatalf("Expected 'constants.ArmIsExistingResourceGroup' not to be set, but it was")
var result = testSubject.Run(stateBag)
if result != multistep.ActionHalt {
t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result)
}
testSubject.Run(stateBag)
if stateBag.Get(constants.ArmIsExistingResourceGroup).(bool) == false {
t.Fatalf("Expected 'constants.ArmIsExistingResourceGroup' to be set to true, but it wasn't.")
if _, ok := stateBag.GetOk(constants.Error); ok == false {
t.Fatalf("Expected the step to set stateBag['%s'], but it was not.", constants.Error)
}
}
@ -137,6 +187,23 @@ func createTestStateBagStepCreateResourceGroup() multistep.StateBag {
stateBag.Put(constants.ArmLocation, "Unit Test: Location")
stateBag.Put(constants.ArmResourceGroupName, "Unit Test: ResourceGroupName")
stateBag.Put(constants.ArmIsExistingResourceGroup, false)
value := "Unit Test: Tags"
tags := map[string]*string{
"tag01": &value,
}
stateBag.Put(constants.ArmTags, &tags)
return stateBag
}
func createTestExistingStateBagStepCreateResourceGroup() multistep.StateBag {
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{

View File

@ -42,7 +42,6 @@ func (s *StepDeleteOSDisk) deleteBlob(storageContainerName string, blobName stri
}
func (s *StepDeleteOSDisk) deleteManagedDisk(resourceGroupName string, imageName string) error {
s.say("In the deleting part")
xs := strings.Split(imageName, "/")
diskName := xs[len(xs)-1]
_, errChan := s.client.DisksClient.Delete(resourceGroupName, diskName, nil)
@ -70,15 +69,14 @@ func (s *StepDeleteOSDisk) Run(state multistep.StateBag) multistep.StepAction {
err = s.deleteManaged(resourceGroupName, osDisk)
if err != nil {
s.say("Failed to delete the managed OS Disk!")
return multistep.ActionHalt
return processStepResult(err, s.error, state)
}
s.say("After deleting")
return multistep.ActionContinue
}
u, err := url.Parse(osDisk)
if err != nil {
s.say("Failed to parse the OS Disk's VHD URI!")
return multistep.ActionHalt
return processStepResult(err, s.error, state)
}
xs := strings.Split(u.Path, "/")

View File

@ -1,6 +1,7 @@
package arm
import (
"errors"
"fmt"
"testing"
@ -103,6 +104,77 @@ func TestStepDeleteOSDiskShouldHandleComplexStorageContainerNames(t *testing.T)
}
}
func TestStepDeleteOSDiskShouldPassIfManagedDiskInTempResourceGroup(t *testing.T) {
var testSubject = &StepDeleteOSDisk{
delete: func(string, string) error { return nil },
say: func(message string) {},
error: func(e error) {},
}
stateBag := new(multistep.BasicStateBag)
stateBag.Put(constants.ArmOSDiskVhd, "subscriptions/123-456-789/resourceGroups/existingresourcegroup/providers/Microsoft.Compute/disks/osdisk")
stateBag.Put(constants.ArmIsManagedImage, true)
stateBag.Put(constants.ArmIsExistingResourceGroup, false)
stateBag.Put(constants.ArmResourceGroupName, "testgroup")
var result = testSubject.Run(stateBag)
if result != multistep.ActionContinue {
t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result)
}
if _, ok := stateBag.GetOk(constants.Error); ok == true {
t.Fatalf("Expected the step to not set stateBag['%s'], but it was.", constants.Error)
}
}
func TestStepDeleteOSDiskShouldFailIfManagedDiskInExistingResourceGroupFailsToDelete(t *testing.T) {
var testSubject = &StepDeleteOSDisk{
delete: func(string, string) error { return nil },
say: func(message string) {},
error: func(e error) {},
deleteManaged: func(string, string) error { return errors.New("UNIT TEST FAIL!") },
}
stateBag := new(multistep.BasicStateBag)
stateBag.Put(constants.ArmOSDiskVhd, "subscriptions/123-456-789/resourceGroups/existingresourcegroup/providers/Microsoft.Compute/disks/osdisk")
stateBag.Put(constants.ArmIsManagedImage, true)
stateBag.Put(constants.ArmIsExistingResourceGroup, true)
stateBag.Put(constants.ArmResourceGroupName, "testgroup")
var result = testSubject.Run(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 not stateBag['%s'], but it was.", constants.Error)
}
}
func TestStepDeleteOSDiskShouldFailIfManagedDiskInExistingResourceGroupIsDeleted(t *testing.T) {
var testSubject = &StepDeleteOSDisk{
delete: func(string, string) error { return nil },
say: func(message string) {},
error: func(e error) {},
deleteManaged: func(string, string) error { return nil },
}
stateBag := new(multistep.BasicStateBag)
stateBag.Put(constants.ArmOSDiskVhd, "subscriptions/123-456-789/resourceGroups/existingresourcegroup/providers/Microsoft.Compute/disks/osdisk")
stateBag.Put(constants.ArmIsManagedImage, true)
stateBag.Put(constants.ArmIsExistingResourceGroup, true)
stateBag.Put(constants.ArmResourceGroupName, "testgroup")
var result = testSubject.Run(stateBag)
if result != multistep.ActionContinue {
t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result)
}
if _, ok := stateBag.GetOk(constants.Error); ok == true {
t.Fatalf("Expected the step to not set stateBag['%s'], but it was.", constants.Error)
}
}
func DeleteTestStateBagStepDeleteOSDisk(osDiskVhd string) multistep.StateBag {
stateBag := new(multistep.BasicStateBag)
stateBag.Put(constants.ArmOSDiskVhd, osDiskVhd)

View File

@ -23,6 +23,7 @@ const (
ArmPublicIPAddressName string = "arm.PublicIPAddressName"
ArmResourceGroupName string = "arm.ResourceGroupName"
ArmIsResourceGroupCreated string = "arm.IsResourceGroupCreated"
ArmDoubleResourceGroupNameSet string = "arm.DoubleResourceGroupNameSet"
ArmStorageAccountName string = "arm.StorageAccountName"
ArmTags string = "arm.Tags"
ArmVirtualMachineCaptureParameters string = "arm.VirtualMachineCaptureParameters"