|
| 1 | +# Copyright 2025 The MathWorks, Inc. |
| 2 | +function Get-IMDSV2Token { |
| 3 | + <# |
| 4 | + .SYNOPSIS |
| 5 | + Retrieves an IMDSv2 token from the EC2 instance metadata service. |
| 6 | +
|
| 7 | + .DESCRIPTION |
| 8 | + This function sends a request to the EC2 instance metadata service to obtain an IMDSv2 token. |
| 9 | + The token is used for subsequent requests to retrieve instance metadata. |
| 10 | +
|
| 11 | + .PARAMETER TokenDuration |
| 12 | + The desired duration of the token in seconds. |
| 13 | +
|
| 14 | + .RETURNS |
| 15 | + Returns the IMDSv2 token as a string. |
| 16 | +
|
| 17 | + .EXAMPLE |
| 18 | + $token = Get-IMDSV2Token -TokenDuration 300 |
| 19 | + #> |
| 20 | + param ( |
| 21 | + [string]$TokenDuration |
| 22 | + ) |
| 23 | + $Token = Invoke-RestMethod -Headers @{"X-aws-ec2-metadata-token-ttl-seconds" = "$TokenDuration"} -Method Put -Uri "http://169.254.169.254/latest/api/token" |
| 24 | + return $Token |
| 25 | +} |
| 26 | + |
| 27 | +function Get-MATLABSourceFiles { |
| 28 | + <# |
| 29 | + .SYNOPSIS |
| 30 | + Downloads MATLAB source files from an S3 URL and extracts them to a specified destination. |
| 31 | +
|
| 32 | + .PARAMETER SourceUrl |
| 33 | + The S3 URL of the zip file containing MATLAB source files. |
| 34 | +
|
| 35 | + .PARAMETER Destination |
| 36 | + The local directory where the source files will be extracted. |
| 37 | +
|
| 38 | + .EXAMPLE |
| 39 | + Get-MATLABSourceFiles -SourceUrl "s3://mybucket/matlab-source.zip" -Destination "C:\MATLABSource" |
| 40 | + #> |
| 41 | + param ( |
| 42 | + [string]$SourceUrl, |
| 43 | + [string]$Destination |
| 44 | + ) |
| 45 | + New-Item -Path "$Destination" -ItemType Directory -Force |
| 46 | + aws s3 cp "$SourceUrl" "$Destination\source.zip" |
| 47 | + Expand-Archive -Path "$Destination\source.zip" -DestinationPath "$Destination" -Force |
| 48 | + Remove-Item -Path "$Destination\source.zip" |
| 49 | +} |
| 50 | + |
| 51 | +function Wait-VolumeAttachment { |
| 52 | + <# |
| 53 | + .SYNOPSIS |
| 54 | + Waits for an EBS volume to be attached to an EC2 instance. |
| 55 | +
|
| 56 | + .DESCRIPTION |
| 57 | + This function polls the AWS EC2 API to check the attachment status of a specified volume to a specified instance. |
| 58 | + It continues checking until the volume is attached or the timeout is reached. |
| 59 | +
|
| 60 | + .PARAMETER VolumeId |
| 61 | + The ID of the EBS volume to check. |
| 62 | +
|
| 63 | + .PARAMETER InstanceId |
| 64 | + The ID of the EC2 instance to which the volume should be attached. |
| 65 | +
|
| 66 | + .PARAMETER Region |
| 67 | + The AWS region where the volume and instance are located. |
| 68 | +
|
| 69 | + .PARAMETER TimeoutSeconds |
| 70 | + The maximum time to wait for the attachment, in seconds. Default is 300 seconds (5 minutes). |
| 71 | +
|
| 72 | + .EXAMPLE |
| 73 | + Wait-VolumeAttachment -VolumeId "vol-1234567890abcdef0" -InstanceId "i-1234567890abcdef0" -Region "us-west-2" |
| 74 | + #> |
| 75 | + param ( |
| 76 | + [string]$VolumeId, |
| 77 | + [string]$InstanceId, |
| 78 | + [string]$Region, |
| 79 | + [int]$TimeoutSeconds = 300 |
| 80 | + ) |
| 81 | + |
| 82 | + $StartTime = Get-Date |
| 83 | + $EndTime = $StartTime.AddSeconds($TimeoutSeconds) |
| 84 | + |
| 85 | + while ((Get-Date) -lt $EndTime) { |
| 86 | + $AttachmentStatus = $(aws ec2 describe-volumes --region $Region --volume-ids $VolumeId --query "Volumes[0].Attachments[?InstanceId=='$InstanceId'].State" --output text) |
| 87 | + if ($AttachmentStatus -eq 'attached') { |
| 88 | + return |
| 89 | + } |
| 90 | + Start-Sleep -Seconds 5 |
| 91 | + } |
| 92 | + throw "Failed to attach volume $VolumeID to instance $InstanceID." |
| 93 | +} |
| 94 | + |
| 95 | +function Mount-DataDrive { |
| 96 | + <# |
| 97 | + .SYNOPSIS |
| 98 | + Creates and mounts an EBS volume to an EC2 instance and assigns it a specified drive letter. |
| 99 | +
|
| 100 | + .DESCRIPTION |
| 101 | + This function creates a new 128GB gp3 EBS volume in the same availability zone as the EC2 instance, |
| 102 | + attaches it to the instance, initializes the disk, creates a partition, formats it with NTFS, |
| 103 | + and assigns it the specified drive letter. |
| 104 | +
|
| 105 | + .PARAMETER DriveToMount |
| 106 | + The drive letter to assign to the newly created and mounted volume. |
| 107 | +
|
| 108 | + .EXAMPLE |
| 109 | + Mount-DataDrive -DriveToMount "M" |
| 110 | + #> |
| 111 | + param ( |
| 112 | + [string]$DriveToMount |
| 113 | + ) |
| 114 | + |
| 115 | + $IMDSToken = Get-IMDSV2Token -TokenDuration 300 |
| 116 | + |
| 117 | + $InstanceID = Invoke-RestMethod -Headers @{"X-aws-ec2-metadata-token" = $IMDSToken} -Method Get -Uri "http://169.254.169.254/latest/meta-data/instance-id" |
| 118 | + $Region = Invoke-RestMethod -Headers @{"X-aws-ec2-metadata-token" = $IMDSToken} -Method Get -Uri "http://169.254.169.254/latest/meta-data/placement/region" |
| 119 | + $AvailabilityZone = Invoke-RestMethod -Headers @{"X-aws-ec2-metadata-token" = $IMDSToken} -Method Get -Uri "http://169.254.169.254/latest/meta-data/placement/availability-zone" |
| 120 | + |
| 121 | + $VolumeID=$(aws ec2 create-volume --size 128 --volume-type gp3 --availability-zone $AvailabilityZone --query "VolumeId" --output text) |
| 122 | + |
| 123 | + aws ec2 wait volume-available --region $Region --volume-ids $VolumeID |
| 124 | + |
| 125 | + aws ec2 attach-volume --region $Region --volume-id $VolumeID --instance-id $InstanceID --device xvdf |
| 126 | + |
| 127 | + # Wait for the volume to attach |
| 128 | + try { |
| 129 | + Wait-VolumeAttachment -VolumeId $VolumeID -InstanceId $InstanceID -Region $Region |
| 130 | + Write-Output "Volume $VolumeId is successfully attached to the instance $InstanceId." |
| 131 | + } catch { |
| 132 | + throw "An error occurred while waiting for the volume $VolumeID to attach to instance $InstanceID : $_" |
| 133 | + } |
| 134 | + |
| 135 | + aws ec2 modify-instance-attribute --region $Region --instance-id $InstanceID --block-device-mappings '[{\"DeviceName\":\"xvdf\",\"Ebs\":{\"DeleteOnTermination\":true}}]' |
| 136 | + |
| 137 | + # AWS formats the serial number of disk in the format "volXXXX" |
| 138 | + $FormattedVolumeID = $VolumeID.Replace("-", "") |
| 139 | + |
| 140 | + # Find the physical disk by matching the formatted volume ID with the serial number |
| 141 | + $Disk = Get-PhysicalDisk | Where-Object { |
| 142 | + $_.SerialNumber -like "*$FormattedVolumeID*" |
| 143 | + } |
| 144 | + |
| 145 | + if ($Disk) { |
| 146 | + # Get the disk number |
| 147 | + $DiskNumber = ($Disk | Get-Disk).Number |
| 148 | + Stop-Service -Name ShellHWDetection |
| 149 | + # Initialize the disk, create a Partition, and format it |
| 150 | + Initialize-Disk -Number $DiskNumber -PartitionStyle MBR -PassThru | |
| 151 | + New-Partition -DriveLetter "$DriveToMount" -UseMaximumSize | |
| 152 | + Format-Volume -FileSystem NTFS -NewFileSystemLabel "MATLAB Source Volume" -Confirm:$false |
| 153 | + |
| 154 | + Start-Service -Name ShellHWDetection |
| 155 | + } else { |
| 156 | + Write-Output "No disk found with the volume ID: $FormattedVolumeID" |
| 157 | + } |
| 158 | + |
| 159 | +} |
| 160 | + |
| 161 | + |
| 162 | +function Dismount-DataDrive { |
| 163 | + <# |
| 164 | + .SYNOPSIS |
| 165 | + Dismounts and deletes an EBS volume associated with a given drive letter. |
| 166 | +
|
| 167 | + .DESCRIPTION |
| 168 | + This function takes a drive letter as input, finds the corresponding EBS volume, |
| 169 | + detaches it from the EC2 instance, and then deletes the volume. |
| 170 | +
|
| 171 | + .PARAMETER DriveLetter |
| 172 | + The drive letter of the volume to be dismounted and deleted. |
| 173 | +
|
| 174 | + .EXAMPLE |
| 175 | + Dismount-DataDrive -DriveLetter "M" |
| 176 | + #> |
| 177 | + param ( |
| 178 | + [string]$DriveLetter |
| 179 | + ) |
| 180 | + |
| 181 | + # Retrieve the serial number of the disk |
| 182 | + $Partition = Get-Partition | Where-Object { $_.DriveLetter -eq $DriveLetter } |
| 183 | + |
| 184 | + # Check if there's a drive with the specified letter |
| 185 | + if (-not $Partition) { |
| 186 | + Write-Output "No drive found with the letter $DriveLetter" |
| 187 | + return |
| 188 | + } |
| 189 | + |
| 190 | + $diskNumber = $Partition.DiskNumber |
| 191 | + $PhysicalDisk = Get-PhysicalDisk | Where-Object { $_.DeviceID -eq $diskNumber } |
| 192 | + $SerialNumber = $PhysicalDisk.SerialNumber |
| 193 | + |
| 194 | + # AWS formats the serial number in the format "volXXXX" |
| 195 | + # Extract the volume ID from the serial number |
| 196 | + if ($SerialNumber -match "^(vol[0-9a-f]+)_") { |
| 197 | + $RawVolumeId = $matches[1] |
| 198 | + |
| 199 | + # Convert to AWS format by inserting a hyphen after 'vol' |
| 200 | + $VolumeId = $RawVolumeId.Insert(3, "-") |
| 201 | + |
| 202 | + Write-Output "The volume ID is: $VolumeId" |
| 203 | + } else { |
| 204 | + Write-Output "Failed to extract a volume ID from the serial number: $SerialNumber" |
| 205 | + return |
| 206 | + } |
| 207 | + |
| 208 | + # Unmount the volume |
| 209 | + Set-Disk -Number $diskNumber -IsOffline $true |
| 210 | + |
| 211 | + $IMDSToken = Get-IMDSV2Token -TokenDuration 300 |
| 212 | + |
| 213 | + # Retrieve instance metadata using IMDSv2 |
| 214 | + $Region = Invoke-RestMethod -Headers @{"X-aws-ec2-metadata-token" = $IMDSToken} -Method Get -Uri "http://169.254.169.254/latest/meta-data/placement/region" |
| 215 | + |
| 216 | + # Detach and delete the volume using AWS CLI |
| 217 | + try { |
| 218 | + aws ec2 detach-volume --volume-id $VolumeId --region $Region |
| 219 | + aws ec2 wait volume-available --region $Region --volume-ids $VolumeId |
| 220 | + aws ec2 delete-volume --region $Region --volume-id $VolumeId |
| 221 | + Write-Output "Successfully detached and deleted volume $VolumeId." |
| 222 | + } catch { |
| 223 | + Write-Output "Failed to detach or delete volume ${VolumeId}: $_" |
| 224 | + } |
| 225 | +} |
0 commit comments