From 1f84ea331048754faa0d1966bebc548723f29a75 Mon Sep 17 00:00:00 2001 From: Ivana Yovcheva Date: Tue, 11 Jul 2017 12:00:57 +0300 Subject: [PATCH 1/2] Implement attached windows disk initialization in Azure ARM --- .../blockstore/AbstractVolumeManager.java | 38 ++++++----- .../azure/arm/AzureArmVolumeManager.java | 29 +++++++-- .../test/resources/customscriptextension.json | 63 +++++++++++++++++++ 3 files changed, 106 insertions(+), 24 deletions(-) create mode 100644 blockstore/src/test/resources/customscriptextension.json diff --git a/blockstore/src/main/java/brooklyn/location/blockstore/AbstractVolumeManager.java b/blockstore/src/main/java/brooklyn/location/blockstore/AbstractVolumeManager.java index 4e44f06..f22c783 100644 --- a/blockstore/src/main/java/brooklyn/location/blockstore/AbstractVolumeManager.java +++ b/blockstore/src/main/java/brooklyn/location/blockstore/AbstractVolumeManager.java @@ -73,26 +73,24 @@ public MountedBlockDevice attachAndMountVolume(JcloudsMachineLocation machine, B @Override public void createFilesystem(AttachedBlockDevice attachedDevice, FilesystemOptions filesystemOptions) { JcloudsMachineLocation machine = attachedDevice.getMachine(); - if (!(machine instanceof SshMachineLocation)) { - throw new IllegalStateException("Cannot create filesystem for "+machine+" of type "+machine.getClass().getName()+"; expected "+SshMachineLocation.class.getSimpleName()); - } - - String osDeviceName = getOSDeviceName(attachedDevice.getDeviceSuffix()); - String filesystemType = filesystemOptions.getFilesystemType(); - LOG.debug("Creating filesystem: device={}; osDeviceName={}, config={}", new Object[]{attachedDevice, osDeviceName, filesystemOptions}); - - // NOTE: also adds an entry to fstab so the mount remains available after a reboot. - Map flags = MutableMap.of("allocatePTY", true); - - int exitCode = ((SshMachineLocation)machine).execCommands(flags, "Creating filesystem on volume", ImmutableList.of( - dontRequireTtyForSudo(), - waitForFileCmd(osDeviceName, 60), - installPackage(ImmutableMap.of("yum", "e4fsprogs"), null), - sudo("/sbin/mkfs -F -t " + filesystemType + " " + osDeviceName))); - - if (exitCode != 0) { - throw new RuntimeException(format("Failed to create file system. machine=%s; osDeviceName=%s; filesystemType=%s", - machine, osDeviceName, filesystemType)); + if (machine instanceof SshMachineLocation) { + String osDeviceName = getOSDeviceName(attachedDevice.getDeviceSuffix()); + String filesystemType = filesystemOptions.getFilesystemType(); + LOG.debug("Creating filesystem: device={}; osDeviceName={}, config={}", new Object[]{attachedDevice, osDeviceName, filesystemOptions}); + + // NOTE: also adds an entry to fstab so the mount remains available after a reboot. + Map flags = MutableMap.of("allocatePTY", true); + + int exitCode = ((SshMachineLocation)machine).execCommands(flags, "Creating filesystem on volume", ImmutableList.of( + dontRequireTtyForSudo(), + waitForFileCmd(osDeviceName, 60), + installPackage(ImmutableMap.of("yum", "e4fsprogs"), null), + sudo("/sbin/mkfs -F -t " + filesystemType + " " + osDeviceName))); + + if (exitCode != 0) { + throw new RuntimeException(format("Failed to create file system. machine=%s; osDeviceName=%s; filesystemType=%s", + machine, osDeviceName, filesystemType)); + } } } diff --git a/blockstore/src/main/java/brooklyn/location/blockstore/azure/arm/AzureArmVolumeManager.java b/blockstore/src/main/java/brooklyn/location/blockstore/azure/arm/AzureArmVolumeManager.java index 26be9e4..7c807bd 100644 --- a/blockstore/src/main/java/brooklyn/location/blockstore/azure/arm/AzureArmVolumeManager.java +++ b/blockstore/src/main/java/brooklyn/location/blockstore/azure/arm/AzureArmVolumeManager.java @@ -11,8 +11,10 @@ import com.google.common.base.Optional; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; +import com.google.common.net.UrlEscapers; import org.apache.brooklyn.location.jclouds.JcloudsLocation; import org.apache.brooklyn.location.jclouds.JcloudsMachineLocation; +import org.apache.brooklyn.util.exceptions.Exceptions; import org.apache.brooklyn.util.repeat.Repeater; import org.apache.brooklyn.util.text.Identifiers; import org.apache.brooklyn.util.text.StringShortener; @@ -20,6 +22,7 @@ import org.apache.brooklyn.util.time.Duration; import org.jclouds.azurecompute.arm.AzureComputeApi; import org.jclouds.azurecompute.arm.domain.DataDisk; +import org.jclouds.azurecompute.arm.domain.Deployment; import org.jclouds.azurecompute.arm.domain.Disk; import org.jclouds.azurecompute.arm.domain.ManagedDiskParameters; import org.jclouds.azurecompute.arm.domain.ResourceGroup; @@ -28,12 +31,16 @@ import org.jclouds.azurecompute.arm.domain.VirtualMachine; import org.jclouds.azurecompute.arm.domain.VirtualMachineProperties; import org.jclouds.azurecompute.arm.features.DiskApi; +import org.jclouds.azurecompute.arm.features.DeploymentApi; import org.jclouds.azurecompute.arm.features.ResourceGroupApi; import org.jclouds.azurecompute.arm.features.StorageAccountApi; import org.jclouds.azurecompute.arm.features.VirtualMachineApi; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; @@ -154,9 +161,11 @@ private AttachedBlockDevice createAndAttachBlockDevice(JcloudsMachineLocation ma } int numExistingDisks = coundDataDisks(vm); - int lun = numExistingDisks; // starts from 0, so if have one disk already then next will be "1" + int lun = numExistingDisks; // starts from 0, so if have one disk already then next will be "1" - Disk disk = addDisk(vmApi, diskApi, vm, options.getSizeInGb(), lun); + DeploymentApi deploymentApi = api.getDeploymentApi(resourceGroupName.get()); + + Disk disk = addDisk(vmApi, diskApi, vm, options.getSizeInGb(), lun, deploymentApi); BlockDevice blockDevice = new AzureArmBlockDevice(location, disk, resourceGroupName.get(), storageAccountName); return blockDevice.attachedTo(machine, getVolumeDeviceName(options.getDeviceSuffix())); @@ -190,7 +199,7 @@ private void deleteStorageAccount(AzureComputeApi api, String resourceGroupName, } } - private Disk addDisk(VirtualMachineApi vmApi, DiskApi diskApi, VirtualMachine vm, int diskSizeGB, int lun) { + private Disk addDisk(VirtualMachineApi vmApi, DiskApi diskApi, VirtualMachine vm, int diskSizeGB, int lun, DeploymentApi deploymentApi) { String vmName = vm.name(); VirtualMachineProperties oldProperties = vm.properties(); StorageProfile oldStorageProfile = oldProperties.storageProfile(); @@ -211,7 +220,19 @@ private Disk addDisk(VirtualMachineApi vmApi, DiskApi diskApi, VirtualMachine vm VirtualMachine newVm = vm.toBuilder().properties(newProperties).build(); vmApi.createOrUpdate(vmName, newVm.location(), newVm.properties(), newVm.tags(), newVm.plan()); - return waitDiskToAppear(diskApi, diskName, TIMEOUT); + Disk result = waitDiskToAppear(diskApi, diskName, TIMEOUT); + + if (vm.location().contains("Win")) { //TODO make better check + String deploymentName = "jc" + System.currentTimeMillis(); + try { + String deploymentTemplate = UrlEscapers.urlFormParameterEscaper().escape(new String(Files.readAllBytes(Paths.get("customscriptextension.json")))); + Deployment deployment = deploymentApi.create(deploymentName, deploymentTemplate); + } catch (IOException e) { + Exceptions.propagate("Failed to read customscriptextension.json", e); + } + } + + return result; } private String getRegionName(JcloudsLocation location) { diff --git a/blockstore/src/test/resources/customscriptextension.json b/blockstore/src/test/resources/customscriptextension.json new file mode 100644 index 0000000..f2fecec --- /dev/null +++ b/blockstore/src/test/resources/customscriptextension.json @@ -0,0 +1,63 @@ +{ + "properties": { + "template": { + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "newStorageAccountName": { + "type":"string", + "metadata": { + "description":"Name of the Storage Account" + } + }, + "storageAccountType": { + "type":"string", + "defaultValue":"Standard_LRS", + "allowedValues": [ + "Standard_LRS","Standard_GRS","Standard_ZRS" + ], + "metadata": { + "description": "Storage Account type" + } + }, + "location": { + "type": "string", + "allowedValues": [ + "East US", + "West US", + "West Europe", + "East Asia", + "Southeast Asia" + ], + "metadata": { + "description": "Location of storage accoun" + } + } + }, + "variables": { }, + "resources": [ + { + "type":"Microsoft.Compute/virtualMachines/extensions", + "name":"[concat(variables('vmName'),'/InitialiseDisks')]", + "apiVersion":"api-version=2016-04-30-preview", + "location":"[resourceGroup().location]", + "dependsOn":[ + "[concat('Microsoft.Compute/virtualMachines/', variables('vmName'))]" + ], + "properties":{ + "publisher":"Microsoft.Compute", + "type":"CustomScriptExtension", + "typeHandlerVersion":"1.2", + "settings":{ + "fileUris":[ + "https://ampdisks427.file.core.windows.net/initialize-disk/initialize-disk.ps1" + ], + "commandToExecute": "powershell -ExecutionPolicy Unrestricted -file initialize-disk.ps1" + } + } + } + ], + "outputs": { } + } + } +} \ No newline at end of file From 326f78d54e7695a59b8cbc95d8eed4e8dd73e5b9 Mon Sep 17 00:00:00 2001 From: Ivana Yovcheva Date: Wed, 12 Jul 2017 18:06:25 +0300 Subject: [PATCH 2/2] Initialize windows disk in Azure ARM - simplify code to not use the ARM API --- .../blockstore/AbstractVolumeManager.java | 57 ++++++++++------- .../azure/arm/AzureArmVolumeManager.java | 29 ++------- .../test/resources/customscriptextension.json | 63 ------------------- 3 files changed, 37 insertions(+), 112 deletions(-) delete mode 100644 blockstore/src/test/resources/customscriptextension.json diff --git a/blockstore/src/main/java/brooklyn/location/blockstore/AbstractVolumeManager.java b/blockstore/src/main/java/brooklyn/location/blockstore/AbstractVolumeManager.java index f22c783..c5784f0 100644 --- a/blockstore/src/main/java/brooklyn/location/blockstore/AbstractVolumeManager.java +++ b/blockstore/src/main/java/brooklyn/location/blockstore/AbstractVolumeManager.java @@ -13,7 +13,9 @@ import org.apache.brooklyn.location.jclouds.JcloudsMachineLocation; import org.apache.brooklyn.location.jclouds.JcloudsMachineNamer; import org.apache.brooklyn.location.ssh.SshMachineLocation; +import org.apache.brooklyn.location.winrm.WinRmMachineLocation; import org.apache.brooklyn.util.collections.MutableMap; +import org.apache.brooklyn.util.core.internal.winrm.WinRmToolResponse; import org.jclouds.compute.domain.NodeMetadata; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -91,38 +93,45 @@ public void createFilesystem(AttachedBlockDevice attachedDevice, FilesystemOptio throw new RuntimeException(format("Failed to create file system. machine=%s; osDeviceName=%s; filesystemType=%s", machine, osDeviceName, filesystemType)); } + } else if (machine instanceof WinRmMachineLocation) { + WinRmToolResponse response = ((WinRmMachineLocation)machine).executePsScript("Get-Disk | Where partitionstyle -eq 'raw' | " + + "Initialize-Disk -PartitionStyle MBR -PassThru | New-Partition -AssignDriveLetter -UseMaximumSize | " + + "Format-Volume -FileSystem NTFS -NewFileSystemLabel \"datadisk\" -Confirm:$false"); + if (response.getStatusCode() != 0) { + throw new RuntimeException(format("Failed to initialize disk. machine=%s; filesystemType=%s", + machine, filesystemOptions.getFilesystemType())); + } } } @Override public MountedBlockDevice mountFilesystem(AttachedBlockDevice attachedDevice, FilesystemOptions options) { JcloudsMachineLocation machine = attachedDevice.getMachine(); - if (!(machine instanceof SshMachineLocation)) { - throw new IllegalStateException("Cannot mount filesystem for "+machine+" of type "+machine.getClass().getName()+"; expected "+SshMachineLocation.class.getSimpleName()); - } - - LOG.debug("Mounting filesystem: device={}; options={}", attachedDevice, options); - String osDeviceName = getOSDeviceName(attachedDevice.getDeviceSuffix()); - String mountPoint = options.getMountPoint(); - String filesystemType = options.getFilesystemType(); + if (machine instanceof SshMachineLocation) { - // NOTE: also adds an entry to fstab so the mount remains available after a reboot. - Map flags = MutableMap.of("allocatePTY", true); - int exitCode = ((SshMachineLocation)machine).execCommands(flags, "Mounting EBS volume", ImmutableList.of( - dontRequireTtyForSudo(), - "echo making dir", - sudo("mkdir -p -m 755 " + mountPoint), - "echo updating fstab", - waitForFileCmd(osDeviceName, 60), - "echo \"" + osDeviceName + " " + mountPoint + " " + filesystemType + " noatime 0 0\" | " + sudo("tee -a /etc/fstab"), - "echo mounting device", - sudo("mount " + mountPoint), - "echo device mounted" - )); + LOG.debug("Mounting filesystem: device={}; options={}", attachedDevice, options); + String osDeviceName = getOSDeviceName(attachedDevice.getDeviceSuffix()); + String mountPoint = options.getMountPoint(); + String filesystemType = options.getFilesystemType(); + + // NOTE: also adds an entry to fstab so the mount remains available after a reboot. + Map flags = MutableMap.of("allocatePTY", true); + int exitCode = ((SshMachineLocation)machine).execCommands(flags, "Mounting EBS volume", ImmutableList.of( + dontRequireTtyForSudo(), + "echo making dir", + sudo("mkdir -p -m 755 " + mountPoint), + "echo updating fstab", + waitForFileCmd(osDeviceName, 60), + "echo \"" + osDeviceName + " " + mountPoint + " " + filesystemType + " noatime 0 0\" | " + sudo("tee -a /etc/fstab"), + "echo mounting device", + sudo("mount " + mountPoint), + "echo device mounted" + )); - if (exitCode != 0) { - throw new RuntimeException(format("Failed to mount file system. machine=%s; osDeviceName=%s; mountPoint=%s; filesystemType=%s", - attachedDevice.getMachine(), osDeviceName, mountPoint, filesystemType)); + if (exitCode != 0) { + throw new RuntimeException(format("Failed to mount file system. machine=%s; osDeviceName=%s; mountPoint=%s; filesystemType=%s", + attachedDevice.getMachine(), osDeviceName, mountPoint, filesystemType)); + } } return attachedDevice.mountedAt(options.getMountPoint()); diff --git a/blockstore/src/main/java/brooklyn/location/blockstore/azure/arm/AzureArmVolumeManager.java b/blockstore/src/main/java/brooklyn/location/blockstore/azure/arm/AzureArmVolumeManager.java index 7c807bd..26be9e4 100644 --- a/blockstore/src/main/java/brooklyn/location/blockstore/azure/arm/AzureArmVolumeManager.java +++ b/blockstore/src/main/java/brooklyn/location/blockstore/azure/arm/AzureArmVolumeManager.java @@ -11,10 +11,8 @@ import com.google.common.base.Optional; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; -import com.google.common.net.UrlEscapers; import org.apache.brooklyn.location.jclouds.JcloudsLocation; import org.apache.brooklyn.location.jclouds.JcloudsMachineLocation; -import org.apache.brooklyn.util.exceptions.Exceptions; import org.apache.brooklyn.util.repeat.Repeater; import org.apache.brooklyn.util.text.Identifiers; import org.apache.brooklyn.util.text.StringShortener; @@ -22,7 +20,6 @@ import org.apache.brooklyn.util.time.Duration; import org.jclouds.azurecompute.arm.AzureComputeApi; import org.jclouds.azurecompute.arm.domain.DataDisk; -import org.jclouds.azurecompute.arm.domain.Deployment; import org.jclouds.azurecompute.arm.domain.Disk; import org.jclouds.azurecompute.arm.domain.ManagedDiskParameters; import org.jclouds.azurecompute.arm.domain.ResourceGroup; @@ -31,16 +28,12 @@ import org.jclouds.azurecompute.arm.domain.VirtualMachine; import org.jclouds.azurecompute.arm.domain.VirtualMachineProperties; import org.jclouds.azurecompute.arm.features.DiskApi; -import org.jclouds.azurecompute.arm.features.DeploymentApi; import org.jclouds.azurecompute.arm.features.ResourceGroupApi; import org.jclouds.azurecompute.arm.features.StorageAccountApi; import org.jclouds.azurecompute.arm.features.VirtualMachineApi; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; @@ -161,11 +154,9 @@ private AttachedBlockDevice createAndAttachBlockDevice(JcloudsMachineLocation ma } int numExistingDisks = coundDataDisks(vm); - int lun = numExistingDisks; // starts from 0, so if have one disk already then next will be "1" + int lun = numExistingDisks; // starts from 0, so if have one disk already then next will be "1" - DeploymentApi deploymentApi = api.getDeploymentApi(resourceGroupName.get()); - - Disk disk = addDisk(vmApi, diskApi, vm, options.getSizeInGb(), lun, deploymentApi); + Disk disk = addDisk(vmApi, diskApi, vm, options.getSizeInGb(), lun); BlockDevice blockDevice = new AzureArmBlockDevice(location, disk, resourceGroupName.get(), storageAccountName); return blockDevice.attachedTo(machine, getVolumeDeviceName(options.getDeviceSuffix())); @@ -199,7 +190,7 @@ private void deleteStorageAccount(AzureComputeApi api, String resourceGroupName, } } - private Disk addDisk(VirtualMachineApi vmApi, DiskApi diskApi, VirtualMachine vm, int diskSizeGB, int lun, DeploymentApi deploymentApi) { + private Disk addDisk(VirtualMachineApi vmApi, DiskApi diskApi, VirtualMachine vm, int diskSizeGB, int lun) { String vmName = vm.name(); VirtualMachineProperties oldProperties = vm.properties(); StorageProfile oldStorageProfile = oldProperties.storageProfile(); @@ -220,19 +211,7 @@ private Disk addDisk(VirtualMachineApi vmApi, DiskApi diskApi, VirtualMachine vm VirtualMachine newVm = vm.toBuilder().properties(newProperties).build(); vmApi.createOrUpdate(vmName, newVm.location(), newVm.properties(), newVm.tags(), newVm.plan()); - Disk result = waitDiskToAppear(diskApi, diskName, TIMEOUT); - - if (vm.location().contains("Win")) { //TODO make better check - String deploymentName = "jc" + System.currentTimeMillis(); - try { - String deploymentTemplate = UrlEscapers.urlFormParameterEscaper().escape(new String(Files.readAllBytes(Paths.get("customscriptextension.json")))); - Deployment deployment = deploymentApi.create(deploymentName, deploymentTemplate); - } catch (IOException e) { - Exceptions.propagate("Failed to read customscriptextension.json", e); - } - } - - return result; + return waitDiskToAppear(diskApi, diskName, TIMEOUT); } private String getRegionName(JcloudsLocation location) { diff --git a/blockstore/src/test/resources/customscriptextension.json b/blockstore/src/test/resources/customscriptextension.json deleted file mode 100644 index f2fecec..0000000 --- a/blockstore/src/test/resources/customscriptextension.json +++ /dev/null @@ -1,63 +0,0 @@ -{ - "properties": { - "template": { - "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "newStorageAccountName": { - "type":"string", - "metadata": { - "description":"Name of the Storage Account" - } - }, - "storageAccountType": { - "type":"string", - "defaultValue":"Standard_LRS", - "allowedValues": [ - "Standard_LRS","Standard_GRS","Standard_ZRS" - ], - "metadata": { - "description": "Storage Account type" - } - }, - "location": { - "type": "string", - "allowedValues": [ - "East US", - "West US", - "West Europe", - "East Asia", - "Southeast Asia" - ], - "metadata": { - "description": "Location of storage accoun" - } - } - }, - "variables": { }, - "resources": [ - { - "type":"Microsoft.Compute/virtualMachines/extensions", - "name":"[concat(variables('vmName'),'/InitialiseDisks')]", - "apiVersion":"api-version=2016-04-30-preview", - "location":"[resourceGroup().location]", - "dependsOn":[ - "[concat('Microsoft.Compute/virtualMachines/', variables('vmName'))]" - ], - "properties":{ - "publisher":"Microsoft.Compute", - "type":"CustomScriptExtension", - "typeHandlerVersion":"1.2", - "settings":{ - "fileUris":[ - "https://ampdisks427.file.core.windows.net/initialize-disk/initialize-disk.ps1" - ], - "commandToExecute": "powershell -ExecutionPolicy Unrestricted -file initialize-disk.ps1" - } - } - } - ], - "outputs": { } - } - } -} \ No newline at end of file