Программно установите буквы дисков Windows для томов EBS с помощью Terraform, Chef или Powershell

Я использую terraform и chef для создания нескольких томов aws ebs и присоединения их к экземпляру EC2.

Проблема в том, что я хочу дать каждому тому ebs определенную букву диска Windows. Проблема в том, что когда экземпляр EC2 создается, окно просто дает ему последовательные буквы дисков (D, E, F и т. Д.)

Некоторые диски имеют одинаковый размер, поэтому я не могу переименовать их в зависимости от размера диска. Кто-нибудь знает, как это сделать с помощью terraform или chef. Мой google foo ничего не находит.

Конечно, это должно придумать другие люди?

Я действительно видел ссылку на использование графического интерфейса Windows EC2Config для их установки, но все дело в том, чтобы автоматизировать процесс, так как в конечном итоге я хочу, чтобы шеф-повар установил SQL-сервер, и ожидается, что определенные данные будут отправляться на определенные буквы дисков.

Кажется, это работает - хотя мне интересно, нет ли более простого способа.

function Convert-SCSITargetIdToDeviceName
{
param([int]$SCSITargetId)
If ($SCSITargetId -eq 0) {
    return "/dev/sda1"
}
$deviceName = "xvd"
If ($SCSITargetId -gt 25) {
    $deviceName += [char](0x60 + [int]($SCSITargetId / 26))
}
$deviceName += [char](0x61 + $SCSITargetId % 26)
return $deviceName
}

Get-WmiObject -Class Win32_DiskDrive | ForEach-Object {
$DiskDrive = $_
$Volumes = Get-WmiObject -Query "ASSOCIATORS OF {Win32_DiskDrive.DeviceID='$($DiskDrive.DeviceID)'} WHERE AssocClass=Win32_DiskDriveToDiskPartition" | ForEach-Object {
    $DiskPartition = $_
    Get-WmiObject -Query "ASSOCIATORS OF {Win32_DiskPartition.DeviceID='$($DiskPartition.DeviceID)'} WHERE AssocClass=Win32_LogicalDiskToPartition"
}
If ($DiskDrive.PNPDeviceID -like "*PROD_PVDISK*") {
    $BlockDeviceName = Convert-SCSITargetIdToDeviceName($DiskDrive.SCSITargetId)
    If ($BlockDeviceName -eq "xvdf") { $drive = gwmi win32_volume -Filter "DriveLetter = '$($Volumes.DeviceID)'"; Set-WmiInstance -input $drive -Arguments @{DriveLetter="D:"; Label="SQL Data"} };
    If ($BlockDeviceName -eq "xvdg") { $drive = gwmi win32_volume -Filter "DriveLetter = '$($Volumes.DeviceID)'"; Set-WmiInstance -input $drive -Arguments @{DriveLetter="L:"; Label="SQL Logs"} };
    If ($BlockDeviceName -eq "xvdh") { $drive = gwmi win32_volume -Filter "DriveLetter = '$($Volumes.DeviceID)'"; Set-WmiInstance -input $drive -Arguments @{DriveLetter="R:"; Label="Report Data"} };
    If ($BlockDeviceName -eq "xvdi") { $drive = gwmi win32_volume -Filter "DriveLetter = '$($Volumes.DeviceID)'"; Set-WmiInstance -input $drive -Arguments @{DriveLetter="T:"; Label="Temp DB"} };
    If ($BlockDeviceName -eq "xvdj") { $drive = gwmi win32_volume -Filter "DriveLetter = '$($Volumes.DeviceID)'"; Set-WmiInstance -input $drive -Arguments @{DriveLetter="M:"; Label="MSDTC"} };
    If ($BlockDeviceName -eq "xvdk") { $drive = gwmi win32_volume -Filter "DriveLetter = '$($Volumes.DeviceID)'"; Set-WmiInstance -input $drive -Arguments @{DriveLetter="B:"; Label="Backups"} };
} ElseIf ($DiskDrive.PNPDeviceID -like "*PROD_AMAZON_EC2_NVME*") {
    $BlockDeviceName = Get-EC2InstanceMetadata "meta-data/block-device-mapping/ephemeral$($DiskDrive.SCSIPort - 2)"
    If ($BlockDeviceName -eq "xvdf") { $drive = gwmi win32_volume -Filter "DriveLetter = '$($Volumes.DeviceID)'"; Set-WmiInstance -input $drive -Arguments @{DriveLetter="D:"; Label="SQL Data"} };
    If ($BlockDeviceName -eq "xvdg") { $drive = gwmi win32_volume -Filter "DriveLetter = '$($Volumes.DeviceID)'"; Set-WmiInstance -input $drive -Arguments @{DriveLetter="L:"; Label="SQL Logs"} };
    If ($BlockDeviceName -eq "xvdh") { $drive = gwmi win32_volume -Filter "DriveLetter = '$($Volumes.DeviceID)'"; Set-WmiInstance -input $drive -Arguments @{DriveLetter="R:"; Label="Report Data"} };
    If ($BlockDeviceName -eq "xvdi") { $drive = gwmi win32_volume -Filter "DriveLetter = '$($Volumes.DeviceID)'"; Set-WmiInstance -input $drive -Arguments @{DriveLetter="T:"; Label="Temp DB"} };
    If ($BlockDeviceName -eq "xvdj") { $drive = gwmi win32_volume -Filter "DriveLetter = '$($Volumes.DeviceID)'"; Set-WmiInstance -input $drive -Arguments @{DriveLetter="M:"; Label="MSDTC"} };
    If ($BlockDeviceName -eq "xvdk") { $drive = gwmi win32_volume -Filter "DriveLetter = '$($Volumes.DeviceID)'"; Set-WmiInstance -input $drive -Arguments @{DriveLetter="B:"; Label="Backups"} };
} Else {
    write-host "Couldn't find disks";
}
}

person Brad    schedule 24.10.2017    source источник
comment
Вы знаете, как этого добиться вручную? Если вы можете поделиться найденным вручную процессом (с помощью графического интерфейса Windows EC2Config), кто-то может помочь вам перевести его в Terraform или Chef, но в настоящее время этот вопрос включает как вопрос AWS , так и Terraform / Вопрос шеф-повара, поэтому маловероятно, что кто-то знает ответ на обе части.   -  person Martin Atkins    schedule 25.10.2017
comment
Итак, в теме письма есть терраформа, но я также упомянул chef и powershell, потому что я действительно не уверен, как это лучше всего сделать. Это для использования terraform (я сейчас думаю, что, возможно, нет) - для этого, вероятно, потребуется PowerShell и / или шеф-повар.   -  person Brad    schedule 25.10.2017
comment
Я отредактировал исходный вопрос, включив в него (нерабочий) пример PowerShell. Он получает диски, но не устанавливает букву диска или метку. Я считаю, что это потому, что диски и тома разные. Я просто не знаю, как сопоставить одно с другим.   -  person Brad    schedule 25.10.2017
comment
Теперь рабочий пример, хотя мне все еще интересно, лучший ли это способ сделать это. Это кажется довольно запутанным.   -  person Brad    schedule 25.10.2017
comment
@Brad: вам может пригодиться следующий Сопоставление дисков с томами на вашем экземпляре Windows, чтобы выявить различия между дисками и томами. Наши серверы SQL, размещенные на AWS, переназначают буквы дисков, размонтируя их с помощью Remove-PartitionAccessPath -AccessPath "$($WrongDriveLetter):" и повторно монтируя с помощью Set-Partition -DiskNumber $DiskNumber -PartitionNumber $Partition+1 -NewDriveLetter $NewDriveLetter. Помните, что числа Win32_DiskPartition отсчитываются от 0, но Set-Partition ожидает отсчета от 1.   -  person AlwaysLearning    schedule 02.11.2017


Ответы (5)


Если принять во внимание таблицы в этой ссылке: https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/ec2-windows-volumes.html

Вы можете видеть, что на EBS первые строки:

Bus Number 0, Target ID 0, LUN 0 /dev/sda1
Bus Number 0, Target ID 1, LUN 0 xvdb

Диск 0 (/ dev / sda1) всегда настраивается EC2 как C:

Итак, вы знаете, что когда вы запускаете «New-Partition -DiskNumber 1 -UseMaximumSize -IsActive -AssignDriveLetter», вы получите D :.

Итак, если вы подготовите образ AMI с помощью Packer, используя следующие тома в Builders (здесь в этом примере всего два, но вы можете сделать любое количество):

        "launch_block_device_mappings": [{
        "device_name": "/dev/sda1",
        "volume_size": 30,
        "volume_type": "gp2",
        "delete_on_termination": true
    },
    {
        "device_name": "xvdb",
        "volume_size": 30,
        "volume_type": "gp2",
        "delete_on_termination": true    
    }]

.. Вы можете планировать, зная, что xvd [b] на самом деле стоит на две буквы позади того, что будет отображено.

Затем разверните экземпляр EC2 этого многотомного AMI с помощью Terraform и поместите его в разделе user_data ресурса aws_instance:

    user_data = <<EOF
    <powershell>
    Initialize-Disk -Number 1 -PartitionStyle "MBR"
    New-Partition -DiskNumber 1 -UseMaximumSize -IsActive -AssignDriveLetter
    Format-Volume -DriveLetter d -Confirm:$FALSE
    Set-Partition -DriveLetter D -NewDriveLetter S
    </powershell>
    EOF

Строка (и) Set-Partition -DriveLetter D -NewDriveLetter S - это то, что вы используете для переименования известного последовательного диска (ов) на любую букву (буквы), к которым вы привыкли. В моем случае они хотели D: as S: - просто повторите эту строку, чтобы переименовать E: как X: или как угодно.

Надеюсь это поможет.

ОБНОВЛЕНИЕ. Есть еще один способ (Server 2016 up), который я обнаружил, когда обнаружил, что Sysprep уничтожает все сопоставления, запекаемые в образ AMI.

Для сопоставления необходимо предоставить файл DriveLetterMappingConfig.json в C: \ ProgramData \ Amazon \ EC2-Windows \ Launch \ Config. Формат файла:

{
  "driveLetterMapping": [
    {
      "volumeName": "sample volume",
      "driveLetter": "H"
    }
  ]
}

... Только у моих дисков по умолчанию не было volumeName; они были пустыми. Итак, вернемся к 1980-м - старому доброму команде "LABEL". Обозначил диск D: как volume2. Итак, файл выглядит так:

{
  "driveLetterMapping": [
    {
      "volumeName": "volume2",
      "driveLetter": "S"
    }
  ]
}

Запуск C: \ ProgramData \ Amazon \ EC2-Windows \ Launch \ Scripts \ InitializeDisks.ps1 проверил, что это сработало (D: стал S :)

Итак, теперь, вернувшись в Packer, мне нужно также подготовить образ с этим файлом DriveLetterMappingConfig.json в C: \ ProgramData \ Amazon \ EC2-Windows \ Launch \ Config, чтобы убедиться, что вся работа с диском, которую я проделал на AMI S: назад как S: на экземпляре. (Я поместил файл в корзину S3 вместе со всей прочей хренью, которую мы собираемся установить в коробку.)

Я помещаю содержимое диска в .ps1 и вызываю его из инициатора:

{"type": "powershell", "script": "./setup_two_drive_names_c_and_s.ps1"
},

Где указанный выше .ps1:

# Do volume config of the two drives
write-host "Setting up drives..."
Initialize-Disk -Number 1 -PartitionStyle "MBR"
New-Partition -DiskNumber 1 -UseMaximumSize -IsActive -AssignDriveLetter
Format-Volume -DriveLetter d -Confirm:$FALSE
label c: "volume1"
label d: "volume2"
Set-Partition -DriveLetter D -NewDriveLetter S

# Now insert DriveLetterMappingConfig.json file into C:\ProgramData\Amazon\EC2-Windows\Launch\Config to ensure instance starts with correct drive mappings
Write-Host "S3 Download: DriveLetterMappingConfig.json"
Read-S3Object -BucketName ********* -Key DriveLetterMappingConfig.json -File 'c:\temp\DriveLetterMappingConfig.json'
Write-Host "Copying DriveLetterMappingConfig.json to C:\ProgramData\Amazon\EC2-Windows\Launch\Config..."
Copy-Item "c:\temp\DriveLetterMappingConfig.json" -Destination "C:\ProgramData\Amazon\EC2-Windows\Launch\Config\DriveLetterMappingConfig.json" -Force
Write-Host "Set Initialze Disks to run on every boot..."
C:\ProgramData\Amazon\EC2-Windows\Launch\Scripts\InitializeDisks.ps1 -Schedule

Да, нет причин маркировать c: Но я был в ударе ...

Последняя строка с параметром «-Schedule» означает, что это происходит при каждой загрузке.

person Faye Smelter    schedule 24.09.2019
comment
С LaunchConfig вы не можете определить, какой диск имеет букву. И вы не можете настроить несколько дисков. - person EnzoR; 26.03.2021

Мне нужен был Windows Server 2016 с 4 дисками одинакового размера, но мне было все равно, какое блочное устройство станет буквой диска. Ниже приведены шаги, которые я предпринял (используя Packer), чтобы получить это:

Во-первых, в области построителей шаблона добавьте столько блочных устройств, сколько вам нужно (в моем случае - 4 записи в разделе launch_block_device_mapping). Затем в списке провайдеров выполните следующие команды:

  1. инициализировать диски с помощью скрипта, доступного на любом инстансе Windows 2016 Amazon; это переведет каждый диск в оперативный режим, добавит к нему раздел, расширит раздел до максимально возможного размера, отформатирует его и назначит ему букву диска Windows.

    {
        "type": "powershell",        
        "inline": [
            "C:\\ProgramData\\Amazon\\EC2-Windows\\Launch\\Scripts\\InitializeDisks.ps1"        
        ]
    }
    

    Примечания:

    Если вы добавите параметр '-Schedule', диски не будут инициализированы на этом этапе, поскольку этот параметр только добавит сценарий к задаче, запланированной для запуска один раз при следующей загрузке экземпляра. (потом деактивируется).

    Буквы дисков назначаются в алфавитном порядке, начиная с D (поскольку C зарезервирован для корневого диска).

    Порядок, в котором тома присоединяются к экземпляру, не связан с именем блочного устройства и не будет иметь соответствия один на один (xvdb не станет D: \ диск, xvdc не станет E: \ и т. д.)

  2. Присвойте желаемую метку каждой букве уже инициализированных дисков.

    {
        "type": "powershell",
        "inline": [
            "write-output \"Label partitions after initializing disks\"",
            "label C: \"OS\"",
            "label D: \"Programs\"",
            "label E: \"Data\"",
            "label F: \"Backup\"",
            ...
        ]
    }
    

    Примечание. Другой возможный вариант - добавить метки непосредственно в файл DriveLetterMapping.json (доступный в любом Windows 2016 Amazon AMI) перед запуском сценария инициализации дисков (я мог бы не заставить эту работу).

  3. После добавления любых других провайдеров, которые могут вам понадобиться (например, активации компонентов Windows, установки приложений или проверки обновлений Windows), последняя запись в списке провайдеров убедитесь, что добавлены скрипты инициализации экземпляра и SysPrep.

    {
        "type": "powershell",
        "inline": [
            "C:/ProgramData/Amazon/EC2-Windows/Launch/Scripts/InitializeInstance.ps1 -Schedule",
            "C:/ProgramData/Amazon/EC2-Windows/Launch/Scripts/SysprepInstance.ps1 -NoShutdown"
        ]
    }
    

    Примечание. Этот последний шаг относится к EC2Launch и применяется начиная с Windows 2016 и далее. Для более старых версий (например, Windows 2012) синтаксис отличается и основан на EC2Config.

После получения AMI из этой конфигурации буквы дисков любого экземпляра, запускаемого из него, должны быть такими, как нужно.

Если буквы дисков и их метки не сопоставлены должным образом, вы также можете попытаться принудительно перемаркировать диски, используя пользовательские данные экземпляра. Непосредственно перед запуском сценарий PowerShell можно легко передать в виде открытого текста; ниже приведен лишь один из возможных примеров:

<powershell>
write-output "Force re-map of drive letters based on labels, after disk initialization"
# remove drive letters, but keep labels
Get-Volume -Drive D | Get-Partition | Remove-PartitionAccessPath -accesspath "D`:\"
Get-Volume -Drive E | Get-Partition | Remove-PartitionAccessPath -accesspath "E`:\"
Get-Volume -Drive F | Get-Partition | Remove-PartitionAccessPath -accesspath "F`:\"
# add drive letters based on labels
get-volume | where filesystemlabel -match "Programs" | Get-Partition | Set-Partition -NewDriveLetter D
get-volume | where filesystemlabel -match "Data" | Get-Partition | Set-Partition -NewDriveLetter E
get-volume | where filesystemlabel -match "Backup" | Get-Partition | Set-Partition -NewDriveLetter F
</powershell>
person Soo    schedule 06.12.2019

Чуть более сложное решение. Настройка Чтобы это работало

  1. Пометьте каждый том буквой DriveLetter и оцените то, что вы хотите ему присвоить. Без :
  2. Дайте экземпляру EC2 права ec2: DescribeTags и ec2: DescribeVolumes в IAM.
  3. Запустите следующий сценарий, передав его в User-data или создайте ssm-документ и запустите его после загрузки.
Get-Disk|where-Object IsSystem -eq $False|Foreach-Object {
  if ( $_.PartitionStyle -Eq 'RAW') {
      Initialize-Disk -Number $_.Number –PartitionStyle MBR
      Set-Disk -Number $_.Number -IsOffline $False
      $VolumeId=$_.SerialNumber -replace "_[^ ]*$" -replace "vol", "vol-"
      $InstanceId = (Invoke-WebRequest -Uri "http://169.254.169.254/latest/meta-data/instance-id" -UseBasicParsing).Content
      $DriveLetter = Get-EC2Volume -Filter @{Name="volume-id";Values=$VolumeId},@{Name="attachment.instance-id";Values=$instanceId}  |ForEach-Object {$_.Tags}|where Key -eq "DriveLetter"|Select-Object -Property Value |foreach-Object {$_.Value}
      New-Partition -DiskNumber $_.Number -DriveLetter $DriveLetter –UseMaximumSize
      Format-Volume -DriveLetter $DriveLetter
    }
person Manpreet Nehra    schedule 30.04.2020
comment
На мой взгляд, это реальное решение (при условии, что оно полностью работает). Все диски с соответствующими тегами можно инициализировать и сопоставить в соответствии с тегами. Хотя я бы добавил еще и метку с меткой. Престижность. - person EnzoR; 26.03.2021
comment
может потребоваться обновление сейчас с метаданными v2 - person Manpreet Nehra; 02.04.2021

На серверах AWS Windows 2016 и новее вы можете использовать следующую строку в пользовательских данных для инициализации дополнительных томов во время создания EC2.

C:\ProgramData\Amazon\EC2-Windows\Launch\Scripts\InitializeDisks.ps1

Больше информации здесь:

Служба поддержки Amazon

Вышеупомянутый сценарий AWS инициализирует диски только как тип MBR. (мы не можем расширить объем ›2 ТБ с помощью типа MBR)

Моим вариантом использования была инициализация томов типа GPT.

Итак, я закончил тем, что передал приведенный ниже скрипт в userdata и отправил его в файл, сохраненный на диске C (я сослался на предложение Манприта Нехраса для фрейма пользовательского скрипта https://stackoverflow.com/a/61530894/8227788)

$disks = Get-Disk|where-Object  partitionstyle -eq 'RAW' 
foreach ($diski in $disks) {
      Initialize-Disk -Number $diski.Number
      Set-Disk -Number $diski.Number -IsOffline $False
      $VolumeId=$diski.SerialNumber -replace "_[^ ]*$" -replace "vol", "vol-"
      $InstanceId = (Invoke-WebRequest -Uri "http://169.254.169.254/latest/meta-data/instance-id" -UseBasicParsing).Content
      $DriveLetter = (Get-EC2Tag -Filter @{Name="resource-type";Value="volume"},@{Name="resource-id";Value=$VolumeId} | where-object Key -eq "driveletter").value
      New-Partition -DiskNumber $diski.Number -DriveLetter $DriveLetter –UseMaximumSize
      Format-Volume -DriveLetter $DriveLetter
    }
Start-Sleep -s 120
'@
$initializescript | Out-File C:\initializescript.ps1
Start-Sleep -s 30  

Then, I called the above script through AWS SSM by creating and associating it with instance . Below is the code


resource "aws_ssm_association" "initialize" {
  count = length(var.ec2_name)
  name        = var.ssm_document_name
  targets {
    key    = "InstanceIds"
    values = [element(aws_instance.ec2server[*].id, count.index)]
  }
    }


resource "aws_ssm_document" "InitializeDrives" {
  name          = "initializedriveswindows"
  document_type = "Command"

  content = <<DOC
{
  "schemaVersion": "2.2",
  "description": "Run command to initialize drives",
  "parameters": {
    "Message": {
      "type": "String",
      "description": "Run command to initialize drives",
      "default": "Run command to initialize drives"
    }
  },
  "mainSteps": [
    {
      "action": "aws:runPowerShellScript",
      "name": "powershell",
      "inputs": {
        "runCommand": [
          "C:\\initializescript.ps1",
          "Restart-Computer -Force"
        ]
      }
    }
  ]
}
DOC
} ```

I have included sleep time to avoid race issues.
person ashok    schedule 06.07.2020

Сначала мы применяем соглашение о монтировании, которое просто гласит, что для некорневых томов используется соглашение xvdDRIVE для ваших устройств, где DRIVE совпадает с буквой диска, к которому вы хотите подключиться.

   xvdd - D:
   xvde - E:
   xvdm = M:

для поддержки назначения привода .. включая монтаж на уровне пропуска

format the volumes .. with the drive letter or some other convention you like
  we run diskpart with an input file.. but basically
      format fs=ntfs label=D quick

затем обновляем DriveletterConfig.xml или DriveLetterConfig.json (в зависимости от ec2config или ec2launch)

    for xml looks like:
        <Mapping> <VolumeName>D</VolumeName> <DriveLetter>D:</DriveLetter></Mapping>
        <Mapping> <VolumeName>E</VolumeName> <DriveLetter>E:</DriveLetter> </Mapping>
        <Mapping> <VolumeName>M</VolumeName> <DriveLetter>M:</DriveLetter> </Mapping>  
    

пуф

person CBB    schedule 29.04.2021