How can one configure an Azure-native compute virtual machine extension in TypeScript
TypeScriptTo configure an Azure-native compute virtual machine extension in TypeScript using Pulumi, you will need to use the
VirtualMachineExtension
resource from theazure-native
package. This resource allows you to manage extensions for a virtual machine, which can be used to configure post-deployment tasks on VMs such as installing and configuring software, running scripts, and more.Before starting, make sure you have the following prerequisites:
- Pulumi CLI installed and configured for Azure.
- An Azure account with appropriate permissions to create resources.
- Node.js and npm installed to run TypeScript projects.
Below, you will find a Pulumi TypeScript program that defines an Azure virtual machine and adds an extension to it. In this example, I’ll use a simple scenario where we configure a custom script extension to run on the virtual machine. The program assumes you have already created or have details for an existing resource group and virtual network including a subnet where the virtual machine will be placed.
import * as pulumi from "@pulumi/pulumi"; import * as azure_native from "@pulumi/azure-native"; // Create an Azure Resource Group if you don't have one already const resourceGroup = new azure_native.resources.ResourceGroup("myResourceGroup"); // Create a public IP for the VM const publicIp = new azure_native.network.PublicIPAddress("myPublicIp", { resourceGroupName: resourceGroup.name, publicIPAllocationMethod: azure_native.network.IPAllocationMethod.Dynamic, }); // Create a Network Security Group and a rule for allowing SSH access const networkSecurityGroup = new azure_native.network.NetworkSecurityGroup("myNetworkSecurityGroup", { resourceGroupName: resourceGroup.name, }); const networkSecurityRule = new azure_native.network.SecurityRule("myNetworkSecurityRule", { resourceGroupName: resourceGroup.name, networkSecurityGroupName: networkSecurityGroup.name, protocol: azure_native.network.SecurityRuleProtocol.Tcp, sourceAddressPrefix: "0.0.0.0/0", sourcePortRange: "*", destinationAddressPrefix: "*", destinationPortRange: "22", access: azure_native.network.SecurityRuleAccess.Allow, direction: azure_native.network.SecurityRuleDirection.Inbound, priority: 100, }); // Create a Virtual Network and Subnet if not using an existing one const virtualNetwork = new azure_native.network.VirtualNetwork("myVirtualNetwork", { resourceGroupName: resourceGroup.name, addressSpace: { addressPrefixes: ["10.0.0.0/16"], }, }); const subnet = new azure_native.network.Subnet("mySubnet", { resourceGroupName: resourceGroup.name, virtualNetworkName: virtualNetwork.name, addressPrefix: "10.0.1.0/24", }); // Create a Network Interface for the VM const networkInterface = new azure_native.network.NetworkInterface("myNetworkInterface", { resourceGroupName: resourceGroup.name, ipConfigurations: [{ name: "myIpConfiguration", subnet: { id: subnet.id, }, publicIPAddress: { id: publicIp.id, }, }], networkSecurityGroup: { id: networkSecurityGroup.id, }, }); // Create an Azure Virtual Machine const virtualMachine = new azure_native.compute.VirtualMachine("myVirtualMachine", { resourceGroupName: resourceGroup.name, vmSize: "Standard_D2_v3", networkProfile: { networkInterfaces: [{ id: networkInterface.id, primary: true, }], }, storageProfile: { imageReference: { offer: "UbuntuServer", publisher: "Canonical", sku: "18.04-LTS", version: "latest", }, osDisk: { createOption: "FromImage", }, }, osProfile: { computerName: "myvm", adminUsername: "azureuser", adminPassword: "Password1234!", }, location: resourceGroup.location, }); // Add an extension to the Virtual Machine const vmExtension = new azure_native.compute.VirtualMachineExtension("myVMExtension", { resourceGroupName: resourceGroup.name, // This name is the name of the virtual machine vmName: virtualMachine.name, /* The location must match the location of the VM it will be attached to */ location: virtualMachine.location, /* The publisher, type, and typeHandlerVersion fields must be set to values that correspond to an extension you wish to use. This example uses the custom script extension to execute a simple script. You can find more information about Azure VM extensions, including publisher and types here: https://docs.microsoft.com/en-us/azure/virtual-machines/extensions/overview */ publisher: "Microsoft.Azure.Extensions", type: "CustomScript", typeHandlerVersion: "2.0", // Example of settings to configure the script extension behavior settings: { // Replace with the script you want to execute "commandToExecute": "echo Hello World > /tmp/hello", }, // If secure values are needed, they can be provided in `protectedSettings` // For example, if the script requires a password // protectedSettings: { // "secret": "some_secure_value", // }, }); // Export the public IP address of the VM export const publicIpAddress = publicIp.ipAddress;
In this program:
- We create all necessary networking components such as a virtual network, subnet, public IP, network interface, and security group to allow SSH access.
- We define an Ubuntu-based VM with the necessary
storageProfile
for the OS disk and image to be used. - The
VirtualMachineExtension
resource is used to define an extension to run a custom script on the VM after it's provisioned. - The
settings
property of the extension is where you specify the behavior of the extension, such as the script to execute. - The use of
protectedSettings
is commented out for clarity, but it's where you would provide any sensitive data that the script needs.
When this program runs, Pulumi will provision the specified Azure resources and configure the VM extension based on the settings provided. Remember to replace the placeholder values with real values appropriate for your use case, and handle secrets securely by using Pulumi secrets.