After a brief hiatus I’m back and to start things off I wanted to share an example of how to use the new REST API we have created as part of our Purity Operating Environment. The implementation of the REST API provides a simple interface for many of the Purity commands available via the CLI. This may be common knowledge but I wanted to make sure we are all on the same page and understand what REST is before diving into details. REST standards for REpresentational State Transfer (REST) uses HTTP requests to interact with resources within Pure Storage. REST is an architectural style that describes the following constraints:
- Uniform Interface. Individual resources are identified in requests using URIs as resource identifiers. For example:
1volume<br>volume/v1Clients manipulate resources through request methods, such as:
Method Description Example GET List resources. GET volume
POST Create a resource. POST volume/v1
PUT Modify a resource. PUT volume/v1
DELETE Delete a resource. DELETE volume/v1
Requests can include additional parameters, either in the URL or as JSON post data. For example, the snap
query parameter is included in the following request to list all snapshots:
1 |
GET volume?snap=true |
Responses return a response code and data (represented in JSON). For example, the following GET volume/v1
request returns a response code200 OK
and the attribute details for a volume named “v1”:
1 2 3 4 5 6 7 8 9 10 11 |
>> GET volume/v1 << 200 OK [ { “created”: “Tue Jan 28 06:15:23 2014”, “name”: “v1”, “serial”: “CEE061D3B3B23499000101E1”, “size”: 1073741824, “source”: null } ] |
- Stateless. The necessary state to handle a request is contained in the request itself.
- Cacheable. The responses must implicitly or explicitly define themselves as cacheable.
- Client-Server. The uniform interface creates separation between client and server. Clients can be more portable, severs do not need to know anything about user interface or state.
- Layered System. A client cannot tell if it is connected directly to the server; intermediary servers can be used to improve scalability or enforce security policies
The best thing about REST is that it is all about decoupling that tight link between clients and servers, for a full deep dive on REST read Roy T. Fielding’s doctoral dissertation.
The other great thing about REST is that you can call it from Windows PowerShell using the Invoke-RestMethod cmdlet in Windows PowerShell 4.0 (yep latest and greatest). The following PowerShell example is a good start at understanding how to work with our REST APIs. In my previous posts you will notice that I used the SSH-Sessions module to interact with our array by passing CLI commands to execute actions on our FlashArray, not anymore! Poohey on SSH from PowerShell (“not that there’s anything wrong with that” – Jerry Seinfeld).
The authentication model used is based on API tokens. We create an API token using POST auth/apitoken then use POST auth/session with the previously created token to access the FlashArray to perform further operations.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
Clear–Host [System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true } $FlashArrayName = <NAME or IP Address> $AuthAction = @{ password = <Account Name> username = <Account Password> } Write–Host $AuthAction.Values $ApiToken = Invoke–RestMethod –Method Post –Uri “https://${FlashArrayName}/api/1.1/auth/apitoken” –Body $AuthAction $SessionAction = @{ api_token = $ApiToken.api_token } Invoke–RestMethod –Method Post –Uri “https://${FlashArrayName}/api/1.1/auth/session” –Body $SessionAction –SessionVariable Session |
Once we are authenticated and have a REST session established we store that session in the –SessionVariable so that subsequent calls can be issued without re-authentication.
In this first post I am simply showing how to access array information, controllers, view space and volume details. Each of the Invoke-RestMethod calls passes into Format-Table –Autosize to display the information nicely.
1 2 3 4 |
Invoke–RestMethod –Method Get –Uri “https://${FlashArrayName}/api/1.1/array” –WebSession $Session | Format–Table –AutoSize Invoke–RestMethod –Method Get –Uri “https://${FlashArrayName}/api/1.1/array?controllers=true” –WebSession $Session | Format–Table –AutoSize Invoke–RestMethod –Method Get –Uri “https://${FlashArrayName}/api/1.1/array?space=true” –WebSession $Session | Format–Table –AutoSize Invoke–RestMethod –Method Get –Uri “https://${FlashArrayName}/api/1.1/volume” –WebSession $Session | Format–Table –AutoSize |
Whenever you are completed performing operations its time to cleanup, use –Method Delete to delete the session.
The results of all the above PowerShell Invoke-RestMethod calls will net the following output:
Next post will cover taking snapshots and creating new volume copies using the REST API with Invoke-RestMethod.
Now, let’s discuss implementing what I consider a step toward the Pure Storage PowerShell Tool Kit (PPTK). The core functions I have implemented are to connect and disconnect to the FlashArray, create snapshots, create new volumes from scratch or from snapshots and connecting volumes to existing hosts.
Let’s start off by connecting to the array using the Connect-PfaController function. This function takes in the FlashArray IP address or name. The –Username and –Password parameters are optional and default to the FlashArray’s single purpose account for performing actions. If you have enabled Directory Service on the FlashArray you can pass the $env:USERNAME and $env:SESSIONNAME to login with Active Directory; look for another future post on setting up Directory Service using the REST API soon (hmmm Part 3 maybe). I use of “Pfa” which stands for Pure FlashArray to denote that the cmdlet is for Pure Storage.
12345678910111213141516171819202122 | Function Connect-PfaController() { [CmdletBinding()] Param( [Parameter(Mandatory=$True)][ValidateNotNullOrEmpty()][string] $FlashArray, [Parameter()][ValidateNotNullOrEmpty()][string] $Username, [Parameter()][ValidateNotNullOrEmpty()][string] $Password“ ) [System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true } $AuthAction = @{ password = $Username username = $Password } Write-Host $AuthAction.Values $ApiToken = Invoke-RestMethod -Method Post -Uri “https://$FlashArray/api/1.2/auth/apitoken” -Body $AuthAction $SessionAction = @{ api_token = $ApiToken.api_token } Invoke-RestMethod -Method Post -Uri “https://$FlashArray/api/1.2/auth/session” -Body $SessionAction -SessionVariable Session $Global:Session = $Session Invoke-RestMethod -Method Get -Uri “https://$FlashArray/api/1.2/array“ -WebSession $Session | Format-Table -AutoSize} |
Just as your parents always told you clean-up after yourself so with a Connect method always comes a Disconnect method. This will disconnect the current session with the FlashArray.
1234567 | Function Disconnect-PfaController() { [CmdletBinding()] Param( [Parameter(Mandatory=$True)][ValidateNotNullOrEmpty()][string] $FlashArray ) Invoke-RestMethod -Method Delete -Uri “https://${FlashArray}/api/1.2/auth/session” -WebSession $Session} |
Now we have the core connection functionality created we can begin using the WebSession with the FlashArray to perform some useful actions like taking snapshots, creating volumes and such. The first action to perform is to create a snapshot using the New-PfaSnapshot function which takes several parameters. I implemented this function and others to call the Connect-PfaController to make the connection as part of the request then disconnect when completed. There really isn’t a need to only connect to the FlashArray without performing an action. When the connection is made to the FlashArray the Session is stored in a Global:Session variable.
1234567891011121314151617 | Function New-PfaSnapshot() { [CmdletBinding()] Param( [Parameter(Mandatory=$True)][ValidateNotNullOrEmpty()][string] $FlashArray, [Parameter(Mandatory=$True)][ValidateNotNullOrEmpty()][string] $SnapshotVolume, [Parameter(Mandatory=$True)][ValidateNotNullOrEmpty()][string] $SnapshotSuffix ) $Snapshot = $null $Snapshot = [ordered]@{ snap = “true” source = [Object[]]“$SnapshotVolume” suffix = $SnapshotSuffix } | ConvertTo-Json Connect-PfaController -FlashArray $FlashArray Invoke-RestMethod -Method Post -Uri “https://$FlashArray/api/1.2/volume” -Body $Snapshot -WebSession $Session -ContentType “application/json” Disconnect-PfaController -FlashArray $FlashArray} |
Use example
New-PfaSnapshot -FlashArray 0.0.0.0 -SnapshotVolume “SAMPLE” -SnapshotSuffix ([Guid]::NewGuid())
Next is the New-PfaVolume function to create new volumes from scratch just using a name and size. The size needs to be in the format of S, K. M, G, T or P; in the use example I create a 500MB volume using the –Size 500M. I tried to account for the different variations of how the REST API can be used to create a new volume or a new volume based on a source volume. The one TODO I have is to support our Overwrite parameter which allows for an existing volume to be overwritten.
123456789101112131415161718192021222324 | Function New-PfaVolume() { [CmdletBinding()] Param( [Parameter(Mandatory=$True)][ValidateNotNullOrEmpty()][string] $FlashArray, [Parameter(Mandatory=$True)][ValidateNotNullOrEmpty()][string] $Name, [Parameter()][ValidateNotNullOrEmpty()][string] $Size = $null, [Parameter()][ValidateNotNullOrEmpty()][string] $Source = $null #TODO: Add Overwrite support. ) $Volume = $null If($Source) { $Volume = @{ source = $Source } | ConvertTo-Json } Else { $Volume = @{ size = $Size } | ConvertTo-Json } Connect-PfaController -FlashArray $FlashArray Invoke-RestMethod -Method Post -Uri “https://$FlashArray/api/1.2/volume/$Name” -Body $Volume -WebSession $Session -ContentType “application/json” Disconnect-PfaController -FlashArray $FlashArray} |
Use examples
Create a new volume called SAMPLE5 of the size 1TB:
New-PfaVolume -FlashArray 10.21.8.82 -Name “SAMPLE5” -Size 1T
Create a new volume SAMPLE4 based on the source volume SAMPLE1:
New-PfaVolume -FlashArray 10.21.8.82 -Name “SAMPLE6” -Source “SAMPLE1”
Depending on whether a new volume was created from an existing or from scratch it needs to be connected to a host. This function is implemented with the requirement of knowing what hosts are available which is somewhat limiting but will have to suffice for now.
12345678910 | Function Get-PfaHosts() { [CmdletBinding()] Param( [Parameter(Mandatory=$True)][ValidateNotNullOrEmpty()][string] $FlashArray ) Connect-PfaController -FlashArray $FlashArray Invoke-RestMethod -Method Get -Uri “https://$FlashArray/api/1.2/host” -WebSession $Session -ContentType “application/json” | Format-Table -AutoSize Disconnect-PfaController -FlashArray $FlashArray} |
Use example
1 | PS C:>Connect–PfaHost –FlashArray 10.1.1.1. –HostName <NAME> –Volume <NAME> |