Managing Enterprise Storage with Pure Storage Fusion in PowerShell - Building Storage Tiers

In modern IT environments, not all workloads require the same level of storage performance, protection, or cost. Some applications need high performance with aggressive data protection, while others are perfectly fine with lower performance in exchange for cost savings. This tiered approach to storage service delivery is fundamental to efficient infrastructure management.

In my previous post on Fusion, I took an application-centric approach, showing how to deploy SQL Servers using Fusion. Let’s switch gears now and learn how to define a storage service catalog. In this post, I’ll demonstrate how to build a complete storage service catalog using Pure Storage Fusion Presets, offering Bronze, Silver, and Gold tiers with optional replication. We’ll see how to leverage different array types (FlashArray //X and FlashArray //C) to optimize both performance and cost across your fleet.

You can find the source code for this blog post here

Understanding Storage Tiers

Before diving into the implementation, let’s define what each tier represents in our service catalog:

  • Bronze: Cost-optimized storage on FlashArray //C arrays with basic snapshot protection
  • Silver: Balanced performance on FlashArray //X arrays with enhanced snapshot retention
  • Gold: Premium performance with aggressive snapshot and replication policies

Note: The storage tiers here are examples, not best practices. Define your storage tiers to meet your business and technical requirements.

Each tier can be deployed with or without replication, below we’ll define three tiers. Summarized in this chart.

Tier Array Type IOPS Bandwidth Snapshots Replication Use Cases
Bronze //C 10K 200 MB/s 6hr/7d Optional Dev/Test
Silver //X 50K 1 GB/s 2hr/14d 2 hour RPO Production
Gold //X 1M 10 GB/s 30min/30d 15 min RPO Critical

Setting Up Fleet Connections

First, let’s connect to our primary array and and our secondary array and examine our fleet topology:

# Connect to primary array (FlashArray //X)
$PrimaryArrayName = 'sn1-x90r2-f06-27.puretec.purestorage.com'
$SecondaryArrayName = 'sn1-c60-e12-16.puretec.purestorage.com'
$Credential = Import-CliXml -Path "$HOME\FA_Cred.xml"
$PrimaryArray = Connect-Pfa2Array EndPoint $PrimaryArrayName -Credential $Credential -IgnoreCertificateError

Now let’s verify our fleet membership and identify available arrays:

# Retrieve all fleet members visible from the primary array
# Excluding FlashBlade (sn1-s200-c09-33) and sn1-c60-e12-16 which is a FlashArray //C to focus on FlashArray //X systems
$PrimaryFleetInfo = Get-Pfa2FleetMember -Array $PrimaryArray -Filter "Member.Name!='sn1-s200-c09-33' and Member.Name!='sn1-c60-e12-16'"

Write-Output "`nFleet Members from Primary Array perspective:"
$PrimaryFleetInfo.Member.Name

Fleet Members from the Primary Array perspective:
sn1-x90r2-f06-27
sn1-x90r2-f06-33

This gives us a view of our FlashArray //X systems that will host our Silver and Gold tier workloads.

Understanding Replication Targets

For workloads requiring replication, we need to configure the secondary array as a replication target. Let’s verify our replication setup. In the code below, we confirm that each of our FlashArray //X’s has an async-replication connection to the FlashArray //C in our lab. This is our snapshot target.

# Get the remote array object needed for configuring replication targets
# Verify if a replication connection already exists between the arrays
# This checks for async-replication type connections specifically
Write-Output "`nChecking for existing replication connections to $($SecondaryArrayName.Split('.')[0])..." 


# Retrieve the remote array object needed for configuring replication targets
# CurrentFleetOnly ensures we only get arrays within our managed fleet
$remoteArray = Get-Pfa2RemoteArray -Array $PrimaryArray -CurrentFleetOnly $true -Name $SecondaryArrayName.Split('.')[0]
$remoteArray.Name

Get-Pfa2ArrayConnection -Array $PrimaryArray `
 -ContextNames $PrimaryFleetInfo.Member.Name `
 -Filter "Remote.Name='$($remoteArray.Name)' and Type='async-replication' and Status='Connected'"


Id                   : f269a914-00c5-408f-b6ba-a3c4048cdbfd
Name                 : sn1-c60-e12-16
Context              : @{Id='081f096d-1c16-42a6-9855-92678d705a1c'; Name='sn1-x90r2-f06-27'}
Encryption           : unencrypted
EncryptionMode       : 
ManagementAddress    : sn1-c60-e12-16.puretec.purestorage.com
Os                   : Purity//FA
Remote               : @{Id='f269a914-00c5-408f-b6ba-a3c4048cdbfd'; Name='sn1-c60-e12-16'; ResourceType='remote-arrays'}
ReplicationAddresses : {10.21.245.107, 10.21.245.193}
ReplicationTransport : ip
Status               : connected
Throttle             : 
Type                 : async-replication
_Version             : 6.8.7

Id                   : f269a914-00c5-408f-b6ba-a3c4048cdbfd
Name                 : sn1-c60-e12-16
Context              : @{Id='ac5fc11f-8b3b-49a0-8261-43baf50b281b'; Name='sn1-x90r2-f06-33'}
Encryption           : unencrypted
EncryptionMode       : 
ManagementAddress    : sn1-c60-e12-16.puretec.purestorage.com
Os                   : Purity//FA
Remote               : @{Id='f269a914-00c5-408f-b6ba-a3c4048cdbfd'; Name='sn1-c60-e12-16'; ResourceType='remote-arrays'}
ReplicationAddresses : {10.21.245.107, 10.21.245.193}
ReplicationTransport : ip
Status               : connected
Throttle             : 
Type                 : async-replication
_Version             : 6.8.7

Due to a current Type mismatch in the PowerShell module, we need to construct the replication targets parameter as a nested list. We will be using this code in the preset creation below. I’ll update this post with the fixed example once the PowerShell module is updated.

# Build the replication targets structure
$ReplicationTargets = [System.Collections.Generic.List[System.Collections.Generic.List[string]]]::new()
$inner = [System.Collections.Generic.List[string]]::new()
$inner.Add("")
$inner.Add($remoteArray.Name)
$inner.Add("remote-arrays")
$ReplicationTargets.Add($inner)

Bronze Tier: Cost-Optimized Storage

The Bronze tier targets FlashArray //C arrays, providing cost-effective capacity with local data protection.

Key aspects of the Bronze tier:

  • Storage Class: flasharray-c ensures placement on cost-optimized C-series arrays
  • Performance: Limited to 10,000 IOPS and 200 MB/s bandwidth
  • Protection: Snapshots every 6 hours, retained for 7 days
  • Use Cases: Development environments, test systems, archival data

Here’s the preset definition:

$BronzePresetNoRepl = @{
    Array = $PrimaryArray
    ContextNames = 'fsa-lab-fleet1'
    Name = "Compute-Bronze-NoRepl"
    Description = "Bronze tier compute workload without replication"
    WorkloadType = "Custom"

    # QoS Configuration - Conservative limits
    QosConfigurationsName = @("Bronze-QoS")
    QosConfigurationsIopsLimit = @("10000")
    QosConfigurationsBandwidthLimit = @((200MB).ToString())  # 200 MB/s

    # Placement Configuration - Target C-series arrays for cost optimization
    PlacementConfigurationsName = @("Bronze-Placement")
    PlacementConfigurationsStorageClassName = @("flasharray-c")
    PlacementConfigurationsStorageClassResourceType = @("storage-classes")
    PlacementConfigurationsQosConfigurations = @(@("Bronze-QoS"))

    # Volume Configuration
    VolumeConfigurationsName = @("Bronze-Vol")
    VolumeConfigurationsCount = @("1")
    VolumeConfigurationsPlacementConfigurations = @(@("Bronze-Placement"))
    VolumeConfigurationsProvisionedSize = @(500GB)

    # Snapshot Configuration - Basic protection
    SnapshotConfigurationsName = @("Bronze-Snapshots")
    SnapshotConfigurationsRulesEvery = @(([TimeSpan]::FromHours(6).TotalMilliseconds).ToString())
    SnapshotConfigurationsRulesKeepFor = @(([TimeSpan]::FromDays(7).TotalMilliseconds).ToString())

    VolumeConfigurationsSnapshotConfigurations = @(@("Bronze-Snapshots"))

    # Workload Tags
    WorkloadTagsKey = @("tier", "replication", "service-level")
    WorkloadTagsValue = @("bronze", "false", "standard")
}

New-Pfa2PresetWorkload @BronzePresetNoRepl

Silver Tier: Balanced Performance

The Silver tier provides enhanced performance on FlashArray //X arrays, suitable for production workloads:

Silver tier characteristics:

  • Storage Class: flasharray-x for balanced performance
  • Performance: 50,000 IOPS and 1 GB/s bandwidth
  • Protection: 2-hour snapshots and replication with 14-day retention
  • RPO: 2-hour recovery point objective
  • Use Cases: Production databases, application servers, important file shares
# Silver Tier - With Replication
$SilverPresetWithRepl = @{
    Array = $PrimaryArray
    ContextNames = 'fsa-lab-fleet1'
    Name = "Compute-Silver-WithRepl"
    Description = "Silver tier compute workload with bi-hourly replication"
    WorkloadType = "Custom"

    # QoS Configuration - Balanced performance
    QosConfigurationsName = @("Silver-QoS")
    QosConfigurationsIopsLimit = @("50000")
    QosConfigurationsBandwidthLimit = @((1GB).ToString())

    # Placement Configuration - Target X-series for performance
    PlacementConfigurationsName = @("Silver-Placement")
    PlacementConfigurationsStorageClassName = @("flasharray-x")
    PlacementConfigurationsStorageClassResourceType = @("storage-classes")
    PlacementConfigurationsQosConfigurations = @(@("Silver-QoS"))

    # Volume Configuration
    VolumeConfigurationsName = @("Silver-Vol")
    VolumeConfigurationsCount = @("1")
    VolumeConfigurationsPlacementConfigurations = @(@("Silver-Placement"))
    VolumeConfigurationsProvisionedSize = @(1TB)

    # Snapshot Configuration
    SnapshotConfigurationsName = @("Silver-Snapshots")
    SnapshotConfigurationsRulesEvery = @(([TimeSpan]::FromHours(2).TotalMilliseconds).ToString())
    SnapshotConfigurationsRulesKeepFor = @(([TimeSpan]::FromDays(14).TotalMilliseconds).ToString())

    # Replication Configuration
    PeriodicReplicationConfigurationsRemoteTargets = $ReplicationTargets
    PeriodicReplicationConfigurationsName = @("Silver-Replication")
    PeriodicReplicationConfigurationsRulesEvery = @(([TimeSpan]::FromHours(2).TotalMilliseconds).ToString())
    PeriodicReplicationConfigurationsRulesKeepFor = @(([TimeSpan]::FromDays(14).TotalMilliseconds).ToString())
    
    VolumeConfigurationsPeriodicReplicationConfigurations = @(@("Silver-Replication"))
    VolumeConfigurationsSnapshotConfigurations = @(@("Silver-Snapshots"))

    # Workload Tags
    WorkloadTagsKey = @("tier", "replication", "service-level", "rpo")
    WorkloadTagsValue = @("silver", "true", "enhanced", "2-hours")
}

New-Pfa2PresetWorkload @SilverPresetWithRepl

Gold Tier: Premium Performance

The Gold tier delivers maximum performance with aggressive data protection:

Gold tier highlights:

  • Performance: Near-unlimited (1M IOPS, 10 GB/s)
  • Protection: 30-minute snapshots with 30-day retention
  • RPO: 15-minute recovery point objective
  • Priority: Tagged as critical for operational awareness
  • Use Cases: Mission-critical databases, real-time analytics, high-frequency trading systems
# Gold Tier - With Replication
$GoldPresetWithRepl = @{
    Array = $PrimaryArray
    ContextNames = 'fsa-lab-fleet1'
    Name = "Compute-Gold-WithRepl"
    Description = "Gold tier compute workload with aggressive replication"
    WorkloadType = "Custom"

    # QoS Configuration - Maximum performance
    QosConfigurationsName = @("Gold-QoS")
    QosConfigurationsIopsLimit = @("1000000")      # 1M IOPS
    QosConfigurationsBandwidthLimit = @((10GB).ToString())  # 10 GB/s

    # Placement Configuration
    PlacementConfigurationsName = @("Gold-Placement")
    PlacementConfigurationsStorageClassName = @("flasharray-x")
    PlacementConfigurationsStorageClassResourceType = @("storage-classes")
    PlacementConfigurationsQosConfigurations = @(@("Gold-QoS"))

    # Volume Configuration
    VolumeConfigurationsName = @("Gold-Vol")
    VolumeConfigurationsCount = @("1")
    VolumeConfigurationsPlacementConfigurations = @(@("Gold-Placement"))
    VolumeConfigurationsProvisionedSize = @(2TB)

    # Snapshot Configuration
    SnapshotConfigurationsName = @("Gold-Snapshots")
    SnapshotConfigurationsRulesEvery = @(([TimeSpan]::FromMinutes(30).TotalMilliseconds).ToString())
    SnapshotConfigurationsRulesKeepFor = @(([TimeSpan]::FromDays(30).TotalMilliseconds).ToString())

    # Replication Configuration
    PeriodicReplicationConfigurationsName = @("Gold-Replication")
    PeriodicReplicationConfigurationsRulesEvery = @(([TimeSpan]::FromMinutes(15).TotalMilliseconds).ToString())
    PeriodicReplicationConfigurationsRulesKeepFor = @(([TimeSpan]::FromDays(30).TotalMilliseconds).ToString())
    
    PeriodicReplicationConfigurationsRemoteTargets = $ReplicationTargets

    VolumeConfigurationsPeriodicReplicationConfigurations = @(@("Gold-Replication"))
    VolumeConfigurationsSnapshotConfigurations = @(@("Gold-Snapshots"))

    # Workload Tags
    WorkloadTagsKey = @("tier", "replication", "service-level", "rpo", "priority")
    WorkloadTagsValue = @("gold", "true", "premium", "15-minutes", "critical")
}

New-Pfa2PresetWorkload @GoldPresetWithRepl

Verifying Preset Creation

With our presets created, you can use the Get-Pfa2PresetWorkload cmdlet with a fleet-wide context of -ContextNames "fsa-lab-fleet1" to get a listing of all of the created presets.

# List all compute tier presets
Write-Output "`nCreated Storage Tier Presets:"
Get-Pfa2PresetWorkload -Array $PrimaryArray -ContextNames "fsa-lab-fleet1" | 
    Select-Object Name, Description | Format-Table -AutoSize

Name                     Description
----                     -----------
Compute-Gold-WithRepl    Gold tier compute workload with aggressive replication
Compute-Silver-WithRepl  Silver tier compute workload with bi-hourly replication
Compute-Bronze-NoRepl    Bronze tier compute workload without replication

Deploying Workloads from Presets

With our service catalog defined, let’s deploy some workloads. Let’s deploy a Gold tier database workload on our X90 array (because it’s always databases ;):

# Get available fleet members for workload placement, excluding the FlashBlade
$FleetMembers = Get-Pfa2FleetMember -Array $PrimaryArray -Filter "Member.Name!='sn1-s200-c09-33'"


Write-Output "`nCreating Gold tier workload..."
$GoldWorkload = @{
    Array        = $PrimaryArray
    ContextNames = ($FleetMembers.Member.Name | Where-Object { $_ -eq 'sn1-x90r2-f06-33' })
    Name         = "Database-Prod-01"
    PresetNames  = @("fsa-lab-fleet1:Compute-Gold-WithRepl")
}

New-Pfa2Workload @GoldWorkload


Creating Gold tier workload...

Id            : 10652a0c-796f-4782-9819-08c987520be9
Name          : Database-Prod-01
Context       : @{Id='ac5fc11f-8b3b-49a0-8261-43baf50b281b'; Name='sn1-x90r2-f06-33'}
Created       : 9/4/2025 5:59:13 PM
Destroyed     : False
Preset        : @{Id='5cc8dc80-4528-43ad-b165-88edf314f4c9'; Name='fsa-lab-fleet1:Compute-Gold-WithRepl'; Revision=1}
Status        : ready
StatusDetails : {}
TimeRemaining : 

Dynamic Volume Addition

One of the best features of Fusion workloads is the ability to add volumes dynamically while maintaining all preset configurations. This has been a troublesome issue for DBAs and storage administrators, as volumes are often added to a host but not added to a Protection Group, which can leave snapshots of databases at risk, by missing the newly added volume in the Protection Group snapshot. Fusion presets prevent this from happening. First, we find the array our workload is running on using Get-Pfa2Workload, then we add the new volume with New-Pfa2Volume. We need to specify the name of the workload with the -WorkloadName parameter, which is the name of the workload we just deployed, Database-Prod-01, and also the workload configuration using -WorkloadConfiguration and a value of Gold-Vol. This will apply our preset policy to the new volume attached to our workload.

$goldContext = (Get-Pfa2Workload -Array $PrimaryArray  -ContextNames $FleetMembers.Member.Name -Name "Database-Prod-01").Context.Name

# Add new volume, notice we don't have to give it a name...all preset configurations will be applied to this volume using the workload configuration.
New-Pfa2Volume -Array $PrimaryArray `
    -ContextNames $goldContext `
    -Provisioned 100GB `
    -WorkloadName "Database-Prod-01" `
    -WorkloadConfiguration 'Gold-Vol'

Adding volumes to Gold workload (Database-Prod-01)...

Id                      : 6436298b-ea11-f6ea-b6d1-d5f88b849209
Name                    : vg-10652a0c-Gold-QoS-vrbmj/vol-10652a0c-Gold-Vol-0001-fk82f
ConnectionCount         : 
Created                 : 9/4/2025 6:00:36 PM
Destroyed               : False
HostEncryptionKeyStatus : none
PriorityAdjustment      : @{PriorityAdjustmentOperator='+'; PriorityAdjustmentValue=0}
Provisioned             : 107374182400
Qos                     : 
Serial                  : AC5FC11F8B3B49A002879B57
Space                   : 
TimeRemaining           : 
Context                 : @{Id='ac5fc11f-8b3b-49a0-8261-43baf50b281b'; Name='sn1-x90r2-f06-33'}
Pod                     : 
Priority                : 0
PromotionStatus         : promoted
ProtocolEndpoint        : 
RequestedPromotionState : promoted
Source                  : 
Subtype                 : regular
VolumeGroup             : @{Id='c0174ce6-fccb-c143-f99e-f8835939cffa'; Name='vg-10652a0c-Gold-QoS-vrbmj'}
Workload                : @{Id='10652a0c-796f-4782-9819-08c987520be9'; Name='Database-Prod-01'; ResourceType='workloads'; _Configuration='Gold-Vol'}   

The new volume automatically inherits:

  • QoS settings from the Volume Group
  • Snapshot policy from the Protection Group
  • Tags and metadata from the workload

Verifying Workload Resources

Let’s examine the volumes that are created as part of our Gold workload deployment, in the output below you’ll see the volume from our initial workload deployment vol-10652a0c-Gold-Vol-0000-lf2sr and the volume added after the deployment vol-10652a0c-Gold-Vol-0001-fk82f:

Get-Pfa2Volume -Array $PrimaryArray -ContextNames $goldContext -Filter "workload.name='Database-Prod-01'" | Format-Table -AutoSize

Id                                   Name                                                        ConnectionCount Created             Destroyed HostEncryptionKeyStatus PriorityAdjustment                                             Provisioned Qos Serial
--                                   ----                                                        --------------- -------             --------- ----------------------- ------------------                                             ----------- --- ------
2242c922-ee4f-a6d8-26a6-ec87f833776d vg-10652a0c-Gold-QoS-vrbmj/vol-10652a0c-Gold-Vol-0000-lf2sr               0 9/4/2025 5:59:14 PM     False none                    @{PriorityAdjustmentOperator='+'; PriorityAdjustmentValue=0} 2199023255552     AC5FC11F8B3B49A002879B2E
6436298b-ea11-f6ea-b6d1-d5f88b849209 vg-10652a0c-Gold-QoS-vrbmj/vol-10652a0c-Gold-Vol-0001-fk82f               0 9/4/2025 6:00:36 PM     False none                    @{PriorityAdjustmentOperator='+'; PriorityAdjustmentValue=0}  107374182400     AC5FC11F8B3B49A002879B57

Next, let’s verify that these volumes are correctly configured with snapshot protection by checking their Protection Group membership. Here, you can see the local Protection Group associated with our deployed workload is named pg-10652a0c-Gold-Snapshots-dp9pq and also the remote Protection Group that our snapshots are being replicated to our FlashArray //C with which is pg-10652a0c-Gold-Replication-kdzrt

$PGNames = Get-Pfa2ProtectionGroup -Array $PrimaryArray -ContextNames $FleetMembers.Member.Name -Filter "workload.name='Database-Prod-01'"
$PGNames | Format-Table -AutoSize

Name                               Id                                   Context                                                               Workload                                                                                                                           Destroyed EradicationConfig              HostCount HostGroupCount
----                               --                                   -------                                                               --------                                                                                                                           --------- -----------------              --------- --------------
pg-10652a0c-Gold-Replication-kdzrt 80a5a2a9-d28e-cb5f-9243-b0644020130d @{Id='ac5fc11f-8b3b-49a0-8261-43baf50b281b'; Name='sn1-x90r2-f06-33'} @{Id='10652a0c-796f-4782-9819-08c987520be9'; Name='Database-Prod-01'; ResourceType='workloads'; _Configuration='Gold-Replication'}     False @{ManualEradication='enabled'}         0              0
pg-10652a0c-Gold-Snapshots-dp9pq   69872897-c7c7-3666-fad6-cf828e2c7fb4 @{Id='ac5fc11f-8b3b-49a0-8261-43baf50b281b'; Name='sn1-x90r2-f06-33'} @{Id='10652a0c-796f-4782-9819-08c987520be9'; Name='Database-Prod-01'; ResourceType='workloads'; _Configuration='Gold-Snapshots'}       False @{ManualEradication='enabled'}         0              0

Using Get-Pfa2ProtectionGroupVolume, you get a listing of volumes in a Protection Group. Here is the listing of the volumes in our workload’s Protection Group. You can see that the newly added volume named vol-10652a0c-Gold-Vol-0000-lf2sr is automatically added to the local and remote Protection Groups.

Get-Pfa2ProtectionGroupVolume -Array $PrimaryArray -ContextNames $goldContext -GroupName $PGNames.Name | Format-Table -AutoSize

Context                                                               Group                                                                                   Member
-------                                                               -----                                                                                   ------
@{Id='ac5fc11f-8b3b-49a0-8261-43baf50b281b'; Name='sn1-x90r2-f06-33'} @{Id='80a5a2a9-d28e-cb5f-9243-b0644020130d'; Name='pg-10652a0c-Gold-Replication-kdzrt'} @{Id='2242c922-ee4f-a6d8-26a6-ec87f833776d'; Name='vg-10652a0c-Gold-QoS-vrbmj/vol-10652a0c-Gold-Vol-0000-lf2sr'; Destroyed=False}
@{Id='ac5fc11f-8b3b-49a0-8261-43baf50b281b'; Name='sn1-x90r2-f06-33'} @{Id='80a5a2a9-d28e-cb5f-9243-b0644020130d'; Name='pg-10652a0c-Gold-Replication-kdzrt'} @{Id='6436298b-ea11-f6ea-b6d1-d5f88b849209'; Name='vg-10652a0c-Gold-QoS-vrbmj/vol-10652a0c-Gold-Vol-0001-fk82f'; Destroyed=False}
@{Id='ac5fc11f-8b3b-49a0-8261-43baf50b281b'; Name='sn1-x90r2-f06-33'} @{Id='69872897-c7c7-3666-fad6-cf828e2c7fb4'; Name='pg-10652a0c-Gold-Snapshots-dp9pq'}   @{Id='2242c922-ee4f-a6d8-26a6-ec87f833776d'; Name='vg-10652a0c-Gold-QoS-vrbmj/vol-10652a0c-Gold-Vol-0000-lf2sr'; Destroyed=False}
@{Id='ac5fc11f-8b3b-49a0-8261-43baf50b281b'; Name='sn1-x90r2-f06-33'} @{Id='69872897-c7c7-3666-fad6-cf828e2c7fb4'; Name='pg-10652a0c-Gold-Snapshots-dp9pq'}   @{Id='6436298b-ea11-f6ea-b6d1-d5f88b849209'; Name='vg-10652a0c-Gold-QoS-vrbmj/vol-10652a0c-Gold-Vol-0001-fk82f'; Destroyed=False}

Finally, let’s inspect the Volume Group details to verify our QoS settings are correctly applied we can do this by finding our Volume Group for the workload using Get-Pfa2VolumeGroup to get the Volume Group and then use Get-Pfa2VolumeGroupVolume to list the volumes in our Volume Group and in the output below you can see the newly added volumevol-10652a0c-Gold-Vol-0001-fk82f is automatically added to the Volume Group. Therefore, it will apply our QoS policy.

# The new volume is also added to the Volume Group, which means the QoS policy will apply
$VGNames = Get-Pfa2VolumeGroup -Array $PrimaryArray -ContextNames $goldContext -Filter "workload.name='Database-Prod-01'" 
$VGNames


Id                 : c0174ce6-fccb-c143-f99e-f8835939cffa
Name               : vg-10652a0c-Gold-QoS-vrbmj
Context            : @{Id='ac5fc11f-8b3b-49a0-8261-43baf50b281b'; Name='sn1-x90r2-f06-33'}
Workload           : @{Id='10652a0c-796f-4782-9819-08c987520be9'; Name='Database-Prod-01'; ResourceType='workloads'; _Configuration='Gold-QoS'}
Destroyed          : False
Pod                : 
PriorityAdjustment : @{PriorityAdjustmentOperator='+'; PriorityAdjustmentValue=0}
Qos                : @{BandwidthLimit=10737418240; IopsLimit=1000000}
Space              : @{DataReduction=1; Snapshots=0; ThinProvisioning=1; TotalPhysical=0; TotalProvisioned=2306397437952; TotalReduction=1; TotalUsed=0; Unique=0; UsedProvisioned=2306397437952; Virtual=0}
TimeRemaining      : 
VolumeCount        : 2

Get-Pfa2VolumeGroupVolume -Array $PrimaryArray -ContextNames $goldContext -GroupName $VGNames.Name | Format-List


Context : @{Id='ac5fc11f-8b3b-49a0-8261-43baf50b281b'; Name='sn1-x90r2-f06-33'}
Group   : @{Id='c0174ce6-fccb-c143-f99e-f8835939cffa'; Name='vg-10652a0c-Gold-QoS-vrbmj'}
_Member : @{Id='2242c922-ee4f-a6d8-26a6-ec87f833776d'; Name='vg-10652a0c-Gold-QoS-vrbmj/vol-10652a0c-Gold-Vol-0000-lf2sr'}

Context : @{Id='ac5fc11f-8b3b-49a0-8261-43baf50b281b'; Name='sn1-x90r2-f06-33'}
Group   : @{Id='c0174ce6-fccb-c143-f99e-f8835939cffa'; Name='vg-10652a0c-Gold-QoS-vrbmj'}
_Member : @{Id='6436298b-ea11-f6ea-b6d1-d5f88b849209'; Name='vg-10652a0c-Gold-QoS-vrbmj/vol-10652a0c-Gold-Vol-0001-fk82f'}

Fleet-Wide Workload Visibility

One of Fusion’s key benefits is the ability to view and manage resources across your entire fleet. Here’s some code to get a listing of all of the volumes associated with the workloads deployed in this blog post.

Write-Output "`nFleet-wide view of all workload volumes:"
Get-Pfa2Volume -Array $PrimaryArray -ContextNames $FleetMembers.Member.Name -Filter "workload.name='WebApp*' or workload.name='Database-*' or workload.name='Analytics-*'" |
    Select-Object Name, 
                  @{N='Array';E={$_.Context.Name}}, 
                  @{N='Size(GB)';E={[math]::Round($_.Provisioned/1GB,2)}}, 
                  @{N='Workload';E={$_.Workload.Name}},
                  @{N='VolumeConfig';E={$_.Workload._Configuration}} |
    Sort-Object Name |
    Format-Table -AutoSize

Fleet-wide view of all workload volumes:

Name                                                            Array            Size(GB) Workload         VolumeConfig
----                                                            -----            -------- --------         ------------
vg-10652a0c-Gold-QoS-vrbmj/vol-10652a0c-Gold-Vol-0000-lf2sr     sn1-x90r2-f06-33 2048.000 Database-Prod-01 Gold-Vol
vg-10652a0c-Gold-QoS-vrbmj/vol-10652a0c-Gold-Vol-0001-fk82f     sn1-x90r2-f06-33  100.000 Database-Prod-01 Gold-Vol

This unified view enables:

  • Capacity planning across arrays
  • Performance monitoring by tier
  • Compliance verification
  • Cost allocation by workload

Best Practices for Service Catalogs

When implementing tiered storage services:

  1. Start Simple: Begin with basic tiers and add complexity as needed
  2. Document Clearly: Ensure tier definitions align with business requirements
  3. Monitor Usage: Track which tiers are most popular to optimize offerings
  4. Review Regularly: Adjust performance limits and retention policies based on actual usage
  5. Automate Deployment: Integrate with your service portal or automation platform

Summary

In this post, we’ve built a complete storage service catalog using Pure Storage Fusion Presets, demonstrating:

  • How to create tiered storage offerings (Bronze, Silver, Gold)
  • Leveraging different array types for cost optimization
  • Configuring optional replication for disaster recovery
  • Dynamic volume addition to existing workloads
  • Fleet-wide resource visibility and management

This approach transforms storage from a technical component into a business service, enabling self-service consumption while maintaining governance and best practices.

Stay tuned as we continue exploring how Pure Storage Fusion enables enterprise storage as a service!