Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[azurerm_batch_pool] - support for custom images with the storage_image_reference property #3530

Merged
merged 8 commits into from
Jul 4, 2019
32 changes: 23 additions & 9 deletions azurerm/helpers/azure/batch_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,17 +214,31 @@ func ExpandBatchPoolImageReference(list []interface{}) (*batch.ImageReference, e
}

storageImageRef := list[0].(map[string]interface{})
imageRef := &batch.ImageReference{}

storageImageRefOffer := storageImageRef["offer"].(string)
storageImageRefPublisher := storageImageRef["publisher"].(string)
storageImageRefSku := storageImageRef["sku"].(string)
storageImageRefVersion := storageImageRef["version"].(string)
if storageImageRef["id"] != nil && storageImageRef["id"] != "" {
storageImageRefID := storageImageRef["id"].(string)
imageRef.ID = &storageImageRefID
}

if storageImageRef["offer"] != nil && storageImageRef["offer"] != "" {
storageImageRefOffer := storageImageRef["offer"].(string)
imageRef.Offer = &storageImageRefOffer
}

if storageImageRef["publisher"] != nil && storageImageRef["publisher"] != "" {
storageImageRefPublisher := storageImageRef["publisher"].(string)
imageRef.Publisher = &storageImageRefPublisher
}

if storageImageRef["sku"] != nil && storageImageRef["sku"] != "" {
storageImageRefSku := storageImageRef["sku"].(string)
imageRef.Sku = &storageImageRefSku
}

imageRef := &batch.ImageReference{
Offer: &storageImageRefOffer,
Publisher: &storageImageRefPublisher,
Sku: &storageImageRefSku,
Version: &storageImageRefVersion,
if storageImageRef["version"] != nil && storageImageRef["version"] != "" {
storageImageRefVersion := storageImageRef["version"].(string)
imageRef.Version = &storageImageRefVersion
}

return imageRef, nil
Expand Down
20 changes: 16 additions & 4 deletions azurerm/resource_arm_batch_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,34 +137,35 @@ func resourceArmBatchPool() *schema.Resource {
"id": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
katbyte marked this conversation as resolved.
Show resolved Hide resolved
ValidateFunc: azure.ValidateResourceID,
},

"publisher": {
Type: schema.TypeString,
Required: true,
Optional: true,
ForceNew: true,
ValidateFunc: validate.NoEmptyStrings,
},

"offer": {
Type: schema.TypeString,
Required: true,
Optional: true,
ForceNew: true,
ValidateFunc: validate.NoEmptyStrings,
},

"sku": {
Type: schema.TypeString,
Required: true,
Optional: true,
ForceNew: true,
DiffSuppressFunc: suppress.CaseDifference,
ValidateFunc: validate.NoEmptyStrings,
},

"version": {
Type: schema.TypeString,
Required: true,
Optional: true,
ForceNew: true,
ValidateFunc: validate.NoEmptyStrings,
},
Expand Down Expand Up @@ -382,6 +383,17 @@ func resourceArmBatchPoolCreate(d *schema.ResourceData, meta interface{}) error
return fmt.Errorf("Error creating Batch pool %q (Resource Group %q): %+v", poolName, resourceGroup, err)
}

if imageReference != nil {
// if an image reference ID is specified, the user wants use a custom image. This property is mutually exclusive with other properties.
if imageReference.ID != nil && (imageReference.Offer != nil || imageReference.Publisher != nil || imageReference.Sku != nil || imageReference.Version != nil) {
return fmt.Errorf("Error creating Batch pool %q (Resource Group %q): Properties version, offer, publish cannot be defined when using a custom image id", poolName, resourceGroup)
} else if imageReference.ID == nil && (imageReference.Offer == nil || imageReference.Publisher == nil || imageReference.Sku == nil || imageReference.Version == nil) {
return fmt.Errorf("Error creating Batch pool %q (Resource Group %q): Properties version, offer, publish and sku are mandatory when not using a custom image", poolName, resourceGroup)
}
} else {
return fmt.Errorf("Error creating Batch pool %q (Resource Group %q): image reference property can not be empty", poolName, resourceGroup)
}

if startTaskValue, startTaskOk := d.GetOk("start_task"); startTaskOk {
startTaskList := startTaskValue.([]interface{})
startTask, startTaskErr := azure.ExpandBatchPoolStartTask(startTaskList)
Expand Down
179 changes: 179 additions & 0 deletions azurerm/resource_arm_batch_pool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,36 @@ func TestAccAzureRMBatchPool_validateResourceFileHttpURLWithoutFilePath(t *testi
})
}

func TestAccAzureRMBatchPool_customImage(t *testing.T) {
resourceName := "azurerm_batch_pool.test"
ri := tf.AccRandTimeInt()
rs := acctest.RandString(4)

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testCheckAzureRMBatchPoolDestroy,
Steps: []resource.TestStep{
{
Config: testaccAzureRMBatchPoolCustomImageConfiguration(ri, rs, testLocation()),
Check: resource.ComposeTestCheckFunc(
testCheckAzureRMBatchPoolExists(resourceName),
resource.TestCheckResourceAttr(resourceName, "vm_size", "STANDARD_A1"),
resource.TestCheckResourceAttr(resourceName, "max_tasks_per_node", "2"),
resource.TestCheckResourceAttr(resourceName, "node_agent_sku_id", "batch.node.ubuntu 16.04"),
resource.TestCheckResourceAttr(resourceName, "account_name", fmt.Sprintf("testaccbatch%s", rs)),
resource.TestCheckResourceAttr(resourceName, "auto_scale.#", "0"),
resource.TestCheckResourceAttr(resourceName, "fixed_scale.#", "1"),
resource.TestCheckResourceAttr(resourceName, "fixed_scale.0.target_dedicated_nodes", "2"),
resource.TestCheckResourceAttr(resourceName, "fixed_scale.0.resize_timeout", "PT15M"),
resource.TestCheckResourceAttr(resourceName, "fixed_scale.0.target_low_priority_nodes", "0"),
resource.TestCheckResourceAttr(resourceName, "start_task.#", "0"),
),
},
},
})
}

func testCheckAzureRMBatchPoolExists(name string) resource.TestCheckFunc {
return func(s *terraform.State) error {
// Ensure we have enough information in state to look up in API
Expand Down Expand Up @@ -986,3 +1016,152 @@ resource "azurerm_batch_pool" "test" {

`, rInt, location, rString, rString, rString)
}

func testaccAzureRMBatchPoolCustomImageConfiguration(rInt int, rString string, location string) string {
return fmt.Sprintf(`
resource "azurerm_resource_group" "test" {
name = "testaccRG-%d-batchpool"
location = "%s"
}

resource "azurerm_virtual_network" "test" {
name = "acctestvn-%d"
address_space = ["10.0.0.0/16"]
location = "${azurerm_resource_group.test.location}"
resource_group_name = "${azurerm_resource_group.test.name}"
}

resource "azurerm_subnet" "test" {
name = "internal"
resource_group_name = "${azurerm_resource_group.test.name}"
virtual_network_name = "${azurerm_virtual_network.test.name}"
address_prefix = "10.0.2.0/24"
}

resource "azurerm_public_ip" "test" {
name = "acctestpip%d"
location = "${azurerm_resource_group.test.location}"
resource_group_name = "${azurerm_resource_group.test.name}"
allocation_method = "Dynamic"
domain_name_label = "acctestpip%d"
}

resource "azurerm_network_interface" "testsource" {
name = "acctestnic-%d"
location = "${azurerm_resource_group.test.location}"
resource_group_name = "${azurerm_resource_group.test.name}"

ip_configuration {
name = "testconfigurationsource"
subnet_id = "${azurerm_subnet.test.id}"
private_ip_address_allocation = "Dynamic"
public_ip_address_id = "${azurerm_public_ip.test.id}"
}
}

resource "azurerm_storage_account" "test" {
name = "acctestsa%s"
resource_group_name = "${azurerm_resource_group.test.name}"
location = "${azurerm_resource_group.test.location}"
account_tier = "Standard"
account_replication_type = "LRS"

tags = {
environment = "Dev"
}
}

resource "azurerm_storage_container" "test" {
name = "vhds"
resource_group_name = "${azurerm_resource_group.test.name}"
storage_account_name = "${azurerm_storage_account.test.name}"
container_access_type = "blob"
}

resource "azurerm_virtual_machine" "testsource" {
name = "acctestvm-%d"
location = "${azurerm_resource_group.test.location}"
resource_group_name = "${azurerm_resource_group.test.name}"
network_interface_ids = ["${azurerm_network_interface.testsource.id}"]
vm_size = "Standard_D1_v2"

storage_image_reference {
publisher = "Canonical"
offer = "UbuntuServer"
sku = "16.04-LTS"
version = "latest"
}

storage_os_disk {
name = "myosdisk1"
vhd_uri = "${azurerm_storage_account.test.primary_blob_endpoint}${azurerm_storage_container.test.name}/myosdisk1.vhd"
caching = "ReadWrite"
create_option = "FromImage"
disk_size_gb = "30"
}

os_profile {
computer_name = "acctest-%d"
admin_username = "tfuser"
admin_password = "P@ssW0RD7890"
}

os_profile_linux_config {
disable_password_authentication = false
}

tags = {
environment = "Dev"
cost-center = "Ops"
}
}

resource "azurerm_image" "test" {
name = "acctest-%d"
location = "${azurerm_resource_group.test.location}"
resource_group_name = "${azurerm_resource_group.test.name}"

os_disk {
os_type = "Linux"
os_state = "Generalized"
blob_uri = "${azurerm_virtual_machine.testsource.storage_os_disk.0.vhd_uri}"
size_gb = 30
caching = "None"
}

tags = {
environment = "Dev"
cost-center = "Ops"
}
}

resource "azurerm_batch_account" "test" {
name = "testaccbatch%s"
resource_group_name = "${azurerm_resource_group.test.name}"
location = "${azurerm_resource_group.test.location}"
pool_allocation_mode = "BatchService"

tags = {
env = "test"
}
}

resource "azurerm_batch_pool" "test" {
name = "testaccpool%s"
resource_group_name = "${azurerm_resource_group.test.name}"
account_name = "${azurerm_batch_account.test.name}"
display_name = "Test Acc Pool"
vm_size = "Standard_A1"
max_tasks_per_node = 2
node_agent_sku_id = "batch.node.ubuntu 16.04"

fixed_scale {
target_dedicated_nodes = 2
}

storage_image_reference {
id = "${azurerm_image.test.id}"
}
}
`, rInt, location, rInt, rInt, rInt, rInt, rString, rInt, rInt, rInt, rString, rString)
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ This example provisions the following Resources:
1. A Resource Group
2. A [Storage Account](https://docs.microsoft.com/en-us/azure/batch/batch-api-basics#azure-storage-account)
3. A [Batch Account](https://docs.microsoft.com/en-us/azure/batch/batch-api-basics#account)
4. Two [Batch pools](https://docs.microsoft.com/en-us/azure/batch/batch-api-basics#pool): one with fixed scale and the other with auto-scale.
4. Two [Batch pools](https://docs.microsoft.com/en-us/azure/batch/batch-api-basics#pool): one with fixed scale and the other with auto-scale

## Usage

Expand Down
File renamed without changes.
File renamed without changes.
16 changes: 16 additions & 0 deletions examples/batch/custom-image/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
## Example: Azure Batch with custom image

This example provisions the following Resources:

## Creates

1. A Resource Group
2. A [Batch Account](https://docs.microsoft.com/en-us/azure/batch/batch-api-basics#account)
3. A Custom Virtual Machine image to be used by the Azure Batch Pool
4. A [Batch pool that uses a custom VM image for virtual machines](https://docs.microsoft.com/en-us/azure/batch/batch-custom-images)

## Usage

- Provide values to all variables (credentials and names).
- Create with `terraform apply`
- Destroy all with `terraform destroy --force`
Loading