4

I'm trying to run a bash script on an Azure VM after deploying it with Terraform. I've tried different approaches but none of them have worked. With "custom_data", I assumed that the file will be uploaded and executed, however I'm not even seeing the file inside the VM.

I've also looked at "azurerm_virtual_machine_extension", but this does not give me the option to upload the file, only to execute commands or download from remote location (can't use fileUris due to requirements):

resource "azurerm_virtual_machine_extension" "test" {
  name                 = "hostname"
  location             = "${azurerm_resource_group.test.location}"
  resource_group_name  = "${azurerm_resource_group.test.name}"
  virtual_machine_name = "${azurerm_virtual_machine.test.name}"
  publisher            = "Microsoft.Azure.Extensions"
  type                 = "CustomScript"
  type_handler_version = "2.0"

  settings = <<SETTINGS
    {
        "commandToExecute": "sh my_script.sh"
    }
SETTINGS

  tags = {
    environment = "Production"
  }
}
resource "azurerm_virtual_machine" "middleware_vm" {
    name                  = "${var.middleware_vm}"
    location              = "${var.location}"
    resource_group_name   = "${azurerm_resource_group.middleware.name}"
    network_interface_ids = ["${azurerm_network_interface.middleware.id}"]
    vm_size               = "Standard_DS4_v2"        

    storage_os_disk {
        name              = "centos_os_disk"
        caching           = "ReadWrite"
        create_option     = "FromImage"
        managed_disk_type = "Premium_LRS"
    }

    storage_data_disk {
        name                 = "managed_backup_disk"
        create_option        = "Empty"
        caching              = "ReadWrite"
        disk_size_gb         = "256"  
        managed_disk_type    = "Premium_LRS"
        lun                  = 0
    }

    storage_image_reference {
        publisher = "OpenLogic"
        offer     = "CentOS"
        sku       = "7.5"
        version   = "latest"
    }

    os_profile {
        computer_name  = "${var.middleware_vm}"
        admin_username = "middlewareadmin"
        custom_data    = "${file("scripts/middleware_disk.sh")}"
  }
Mario Jacobo
  • 107
  • 1
  • 2
  • 10

2 Answers2

4

In azurerm_virtual_machine_extension, you can use:

protected_settings = <<PROTECTED_SETTINGS
{
    "script": "${base64encode(file(var.scfile))}"
}
PROTECTED_SETTINGS

Please refer to my answer

Brian Fitzgerald
  • 634
  • 7
  • 14
1

First, the VM extension will just execute the script and do not copy the file to the VM. If you want to copy the script into the VM and then execute it. I will suggest you the Terraform provisioner file and remote-exec.

Here is the example that copies the file into the existing VM and executes the script:

resource "null_resource" "example" {

    connection {
        type = "ssh"
        user = "azureuser"
        password = "azureuser@2018"
        host = "13.92.255.50"
        port = 22
    }
    provisioner "file" {
        source = "script.sh"
        destination = "/tmp/script.sh"
    }

    provisioner "remote-exec" {
        inline = [
            "/bin/bash /tmp/script.sh"
        ]
    }
}

Note: the script should be created in the current directory.

Charles Xu
  • 29,862
  • 2
  • 22
  • 39
  • thanks, however this won't work for us. the VMs cannot be exposed to the internet, that's why I wanted to use "custom_data" or ""azurerm_virtual_machine_extension" – Mario Jacobo Jul 31 '19 at 08:00
  • @MarioJacobo First, there is nothing shows the VM does not expose to the Internet. And you also do not show the exact requirement and which error you got. – Charles Xu Jul 31 '19 at 08:48
  • @MarioJacobo If you do not expose the VM to the internet, how do you use the VM? – Charles Xu Jul 31 '19 at 08:57
  • there is no error whatsoever, it's just that nothing is ran or uploaded to the VM, using custom_data = "${file("scripts/middleware_disk.sh")}". I was hoping to use "custom_data" to upload the file and then "azurerm_virtual_machine_extension" to execute the script. The VM just performs some cron tasks internally and does not need to be exposed to the internet at all, due to sensitive data on disk. I may need to use an ARM template (where I encoded the script to base64) and inject that with Terraform. It's not ideal as but it's the only option I see – Mario Jacobo Jul 31 '19 at 09:36
  • @MarioJacobo If like this, the custom_data is more appropriate. Then you can take a look at [the custom_data in Terraform for the Azure VM](http://teknews.cloud/bootstrapping-azure-vms-with-terraform/). – Charles Xu Jul 31 '19 at 09:51
  • thanks, but for some reason "template_file" does not work anymore in > v0.12. I keep getting ":104,33-34: Invalid character; This character is not used within the language." very strange – Mario Jacobo Jul 31 '19 at 12:01
  • in the end it worked. had no idea that you have to escape all "$" in the bash file. ended up with "$$", so the rendering worked. – Mario Jacobo Jul 31 '19 at 14:19
  • @MarioJacobo Where do you mean that? – Charles Xu Aug 01 '19 at 06:37
  • 1
    after a bit more testing, I decided to use ARM template with "azurerm_template_deployment" as "azurerm_virtual_machine_extension" or "custom_data" didnt work. The ARM template can process all bash scripts base64-encoded. – Mario Jacobo Aug 01 '19 at 12:22