I'm looking to spin up VMs using the node/Javascript SDK for Azure. So far I've had luck with my code and it pretty much works as expected. However I would like to spin up generation 2 / HyperV v2 VMs instead of the default v1. Here's a snippet of my code:
return new Promise((resolve, reject) => {
let resourceClient = new ComputeManagementClient(credentials, azureSubscriptionID);
resourceClient.virtualMachines.createOrUpdate(reourceGroup, name, {
location: location,
osProfile: { computerName: name, adminUsername: 'admin', adminPassword: adminPassword, customData: Buffer.from(prepScript).toString('base64') },
hardwareProfile: { vmSize: 'Standard_B2s' },
HyperVGeneration: 'V2',
storageProfile: {
imageReference: { publisher: 'Canonical', offer: 'UbuntuServer', sku: '18.04-LTS', version: 'latest' },
osDisk: { name: name + '-disk', createOption: 'FromImage' }
},
networkProfile: {
networkInterfaces: [{ id: nic.id, primary: true }]
}
}, function (err, result) {
if (err) {
reject(err);
} else {
resolve(result);
}
});
}
The problem I'm having is with:
HyperVGeneration: 'V2'
as it seems to not even apply. Nor do I get any errors, just a V1 VM is created. The Azure Docs are kind of lacking here: https://learn.microsoft.com/en-us/javascript/api/@azure/arm-compute/hypervgeneration?view=azure-node-latest I've also tried the other parameters such as HyperVGenerationType / Types with the same result.
I figured it out!
I was working off the wrong assumption here. Instead of configuring the VM generation/HyperVGeneration to V2, somehow using a gen2 image sku to base the OS disk off of, automatically configures the VM generation to V2 as well. It also doesn't help the fact that MS calls the same thing by multiple names: VM generation, HyperV generation, image generation.
Anyway the solution is to actually look up all available images which can be installed and pick the correct one from there. To get available images for your region:
az vm image list --all --publisher 'Canonical' --sku '18_04' --output table
Which returns something like:
Offer Publisher Sku Urn Version
-------------------------------------------- ----------- ---------------------------- ------------------------------------------------------------------------------------------- ---------------
0001-com-ubuntu-confidential-vm-experimental Canonical 18_04 Canonical:0001-com-ubuntu-confidential-vm-experimental:18_04:18.04.20210309 18.04.20210309
0001-com-ubuntu-confidential-vm-experimental Canonical 18_04-gen2 Canonical:0001-com-ubuntu-confidential-vm-experimental:18_04-gen2:18.04.20210309 18.04.20210309
0001-com-ubuntu-pro-advanced-sla Canonical 18_04 Canonical:0001-com-ubuntu-pro-advanced-sla:18_04:18.04.20200318 18.04.20200318
0001-com-ubuntu-pro-advanced-sla Canonical 18_04 Canonical:0001-com-ubuntu-pro-advanced-sla:18_04:18.04.20200605 18.04.20200605
...
Another thing of note is that some Ubuntu images have the sku as "18.04" and some "18_04" which further confuses things.
The final solution was this use this snippet in order to put it all together:
return new Promise((resolve, reject) => {
let resourceClient = new ComputeManagementClient(credentials, azureSubscriptionID);
resourceClient.virtualMachines.createOrUpdate(reourceGroup, name, {
location: location,
osProfile: { computerName: name, adminUsername: 'admin', adminPassword: adminPassword, customData: Buffer.from(prepScript).toString('base64') },
hardwareProfile: { vmSize: 'Standard_B2s' },
storageProfile: {
imageReference: { publisher: 'Canonical', offer: 'UbuntuServer', sku: '18_04-lts-gen2', version: 'latest' },
osDisk: { name: name + '-disk', createOption: 'FromImage' }
},
networkProfile: {
networkInterfaces: [{ id: nic.id, primary: true }]
}
}, function (err, result) {
if (err) {
reject(err);
} else {
resolve(result);
}
});
}
Notice how the image sku is 18_04-lts-gen2 instead of 18.04-LTS.