Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/pscloud/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
Release History
===============

1.0.0
+++++
* Stable release.

1.0.0b1
++++++
* Initial release.
53 changes: 47 additions & 6 deletions src/pscloud/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,23 @@

This is an extension to Azure CLI to manage Pure Storage Cloud Azure Native resources.

## Recent Improvements ##

The pscloud CLI has been recently improved for better usability and consistency:

### Enhanced Parameter Usability ###
- **Simplified zone specification**: Use `--zone` or `-z` instead of `--availability-zone`
- **Flattened network parameters**: Use `--subnet-name` and `--vnet-name` directly instead of complex `--vnet-injection` JSON objects
- **Improved parameter names**: Consistent use of `--name` or `-n` across all commands

### Removed Unsupported Features ###
- **Identity parameters removed**: `--system-assigned`, `--user-assigned`, and related identity options have been removed as they are not supported by the Pure Storage Cloud service
- **Wait command removed**: `az pscloud pool wait` has been removed for consistency with other Azure CLI extensions

### Enhanced Validation ###
- **Required parameters**: Key parameters like `--zone`, `--provisioned-bandwidth`, `--reservation-id`, `--subnet-name`, and `--vnet-name` are now properly validated as required
- **Better examples**: All command examples now show realistic Azure resource IDs and cleaner syntax

## How to use ##

For more details about the Pure Storage Cloud resources please visit [documentation on Pure Support](https://support.purestorage.com/bundle/m_azure_native_pure_storage_cloud/page/Pure_Cloud_Block_Store/Azure_Native_Pure_Storage_Cloud/design/c_resources_in_psc.html).
Expand All @@ -10,7 +27,7 @@ For more details about the Pure Storage Cloud resources please visit [documentat

Install this extension using the below CLI command:
```
az extension add --name pscloud --allow-preview
az extension add --name pscloud
```

### Check the version ###
Expand Down Expand Up @@ -65,13 +82,33 @@ This resource represents a block storage array instance, delivered as a service,
To create a Storage Pool, you need to have a virtual network with a delegated subnet to `PureStorage.Block` service.

```bash
az pscloud pool create --resource-group {resource_group} --storage-pool-name {storage_pool_name} --location {location} --availability-zone {availability_zone} --vnet-injection '{{"subnet-id": "{subnet_id}", "vnet-id": "{vnet_id}"}}' --provisioned-bandwidth {bandwidth_mb_per_sec} --reservation-id {reservation_resource_id} --system-assigned --user-assigned {user_assigned_identity_ids} --tags "{key:value}"
az pscloud pool create --resource-group {resource_group} --storage-pool-name {storage_pool_name} --location {location} --zone {availability_zone} --subnet-name {subnet_resource_id} --vnet-name {vnet_resource_id} --provisioned-bandwidth {bandwidth_mb_per_sec} --reservation-id {reservation_resource_id} --tags "{key:value}"
```

**Required Parameters:**
- `--zone` or `-z`: Azure Availability Zone (1, 2, or 3)
- `--subnet-name`: Full Azure resource ID of the delegated subnet
- `--vnet-name`: Full Azure resource ID of the virtual network
- `--provisioned-bandwidth`: Bandwidth in MB/s
- `--reservation-id`: Azure resource ID of the Pure Storage Cloud reservation

**Example with realistic values:**
```bash
az pscloud pool create \
--resource-group myResourceGroup \
--storage-pool-name myStoragePool \
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The example uses the old parameter name --storage-pool-name instead of the standardized --name parameter. For consistency with the PR's goal of parameter standardization and the documented improvements on lines 12 and 154, this should be changed to use --name or -n.

Suggested change
--storage-pool-name myStoragePool \
--name myStoragePool \

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No changes made in create, changes regarding storage pool name have only been made in get-avs-status and get-health status.

--location eastus \
--zone 1 \
--subnet-name /subscriptions/12345678-1234-1234-1234-123456789abc/resourceGroups/myResourceGroup/providers/Microsoft.Network/virtualNetworks/myVnet/subnets/mySubnet \
--vnet-name /subscriptions/12345678-1234-1234-1234-123456789abc/resourceGroups/myResourceGroup/providers/Microsoft.Network/virtualNetworks/myVnet \
--provisioned-bandwidth 100 \
--reservation-id /subscriptions/12345678-1234-1234-1234-123456789abc/providers/PureStorage.Block/reservations/myReservation
```

#### Show a Storage Pool ####

```bash
az pscloud pool show --resource-group {resource_group} --storage-pool-name {storage_pool_name}
az pscloud pool show --resource-group {resource_group} --name {storage_pool_name}
```

#### List Storage Pools ####
Expand All @@ -86,10 +123,12 @@ az pscloud pool list --resource-group {resource_group}
az pscloud pool update --resource-group {resource_group} --name {storage_pool_name} --provisioned-bandwidth {bandwidth_mb_per_sec}
```

**Note:** Identity-related parameters (`--system-assigned`, `--user-assigned`) have been removed as they are not supported by the Pure Storage Cloud service.

#### Delete a Storage Pool ####

```bash
az pscloud pool delete --resource-group {resource_group} --storage-pool-name {storage_pool_name}
az pscloud pool delete --resource-group {resource_group} --name {storage_pool_name}
```

#### Connect a Storage Pool to AVS ####
Expand All @@ -101,15 +140,17 @@ Currently, establishing a connection between a Storage Pool and an Azure VMware
This command provides the health status about the Storage Pool.

```bash
az pscloud pool get-health-status --resource-group {resource_group} --storage-pool-name {storage_pool_name}
az pscloud pool get-health-status --resource-group {resource_group} --name {storage_pool_name}
```

#### Get Storage Pool AVS Status ####

This command provides the current connection status between the Storage Pool and Azure VMware Solution (AVS) resource.

```bash
az pscloud pool get-avs-status --resource-group {resource_group} --storage-pool-name {storage_pool_name}
az pscloud pool get-avs-status --resource-group {resource_group} --name {storage_pool_name}
```

**Note:** You can use either `--name` or `-n` for the storage pool name parameter.

If you have issues, please give feedback by opening an issue at https://github.com/Azure/azure-cli-extensions/issues.
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@

@register_command_group(
"pscloud",
is_preview=True,
)
class __CMDGroup(AAZCommandGroup):
"""Manage Pure Storage Block resources
Expand Down
1 change: 0 additions & 1 deletion src/pscloud/azext_pscloud/aaz/latest/pscloud/_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@

@register_command(
"pscloud list",
is_preview=True,
)
class List(AAZCommand):
"""List reservations by Azure subscription ID
Expand Down
1 change: 0 additions & 1 deletion src/pscloud/azext_pscloud/aaz/latest/pscloud/_show.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@

@register_command(
"pscloud show",
is_preview=True,
)
class Show(AAZCommand):
"""Get a reservation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@

@register_command_group(
"pscloud pool",
is_preview=True,
)
class __CMDGroup(AAZCommandGroup):
"""Manage Storage Pool
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,3 @@
from ._list import *
from ._show import *
from ._update import *
from ._wait import *
74 changes: 23 additions & 51 deletions src/pscloud/azext_pscloud/aaz/latest/pscloud/pool/_create.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,12 @@

@register_command(
"pscloud pool create",
is_preview=True,
)
class Create(AAZCommand):
"""Create a storage pool

:example: StoragePools_Create
az pscloud pool create --resource-group rgpurestorage --storage-pool-name storagePoolname --availability-zone vknyl --vnet-injection "{subnet-id:tnlctolrxdvnkjiphlrdxq,vnet-id:zbumtytyqwewjcyckwqchiypshv}" --provisioned-bandwidth 17 --reservation-id xiowoxnbtcotutcmmrofvgdi --type None --user-assigned-identities "{key4211:{}}" --tags "{key7593:vsyiygyurvwlfaezpuqu}" --location lonlc
az pscloud pool create --resource-group rgpurestorage --storage-pool-name storagePoolname --zone 1 --subnet-name /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/virtualNetworks/{vnetName}/subnets/{subnetName} --vnet-name /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/virtualNetworks/{vnetName} --provisioned-bandwidth 100 --reservation-id /subscriptions/{subscriptionId}/providers/PureStorage.Block/reservations/{reservationName} --location eastus
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The example command in the code uses --storage-pool-name parameter, but according to the PR description and changes to other commands (_get_health_status.py, _get_avs_status.py), the consistent naming should use --name or -n instead. While --storage-pool-name is still supported as an alias (line 52), the example should use the preferred standardized form --name for consistency.

Suggested change
az pscloud pool create --resource-group rgpurestorage --storage-pool-name storagePoolname --zone 1 --subnet-name /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/virtualNetworks/{vnetName}/subnets/{subnetName} --vnet-name /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/virtualNetworks/{vnetName} --provisioned-bandwidth 100 --reservation-id /subscriptions/{subscriptionId}/providers/PureStorage.Block/reservations/{reservationName} --location eastus
az pscloud pool create --resource-group rgpurestorage --name storagePoolname --zone 1 --subnet-name /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/virtualNetworks/{vnetName}/subnets/{subnetName} --vnet-name /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/virtualNetworks/{vnetName} --provisioned-bandwidth 100 --reservation-id /subscriptions/{subscriptionId}/providers/PureStorage.Block/reservations/{reservationName} --location eastus

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No changes made in create, changes regarding storage pool name have only been made in get-avs-status and get-health status.

"""

_aaz_info = {
Expand Down Expand Up @@ -60,58 +59,25 @@ def _build_arguments_schema(cls, *args, **kwargs):
),
)

# define Arg Group "Identity"

_args_schema = cls._args_schema
_args_schema.mi_system_assigned = AAZStrArg(
options=["--system-assigned", "--mi-system-assigned"],
arg_group="Identity",
help="Set the system managed identity.",
blank="True",
)
_args_schema.mi_user_assigned = AAZListArg(
options=["--user-assigned", "--mi-user-assigned"],
arg_group="Identity",
help="Set the user managed identities.",
blank=[],
)

mi_user_assigned = cls._args_schema.mi_user_assigned
mi_user_assigned.Element = AAZStrArg()

# define Arg Group "Properties"

_args_schema = cls._args_schema
_args_schema.availability_zone = AAZStrArg(
options=["--availability-zone"],
_args_schema.zone = AAZStrArg(
options=["-z", "--zone"],
arg_group="Properties",
help="Azure Availability Zone the Pool is located in",
required=True,
)
_args_schema.provisioned_bandwidth = AAZIntArg(
options=["--provisioned-bandwidth"],
arg_group="Properties",
help="Total bandwidth provisioned for the pool, in MB/s",
required=True,
)
_args_schema.reservation_id = AAZStrArg(
options=["--reservation-id"],
arg_group="Properties",
help="Azure resource ID of the Pure Storage Cloud service (reservation resource) this storage pool belongs to",
)
_args_schema.vnet_injection = AAZObjectArg(
options=["--vnet-injection"],
arg_group="Properties",
help="Network properties of the storage pool",
)

vnet_injection = cls._args_schema.vnet_injection
vnet_injection.subnet_id = AAZStrArg(
options=["subnet-id"],
help="Azure resource ID of the Virtual Network subnet where the storage pool will be connected",
required=True,
)
vnet_injection.vnet_id = AAZStrArg(
options=["vnet-id"],
help="Azure resource ID of the Virtual Network in which the subnet is located",
required=True,
)

Expand All @@ -134,6 +100,22 @@ def _build_arguments_schema(cls, *args, **kwargs):

tags = cls._args_schema.tags
tags.Element = AAZStrArg()

# define Arg Group "VnetInjection"

_args_schema = cls._args_schema
_args_schema.subnet_id = AAZStrArg(
options=["--subnet-name"],
arg_group="VnetInjection",
help="Azure resource ID of the Virtual Network subnet where the storage pool will be connected",
required=True,
)
_args_schema.vnet_id = AAZStrArg(
options=["--vnet-name"],
arg_group="VnetInjection",
help="Azure resource ID of the Virtual Network in which the subnet is located",
required=True,
)
Comment on lines +107 to +118
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The parameter option names are misleading and inconsistent with the help text and actual values expected. The parameter options are named --subnet-name and --vnet-name, but the help text describes them as accepting "Azure resource ID" values, and the internal variable names are subnet_id and vnet_id.

The documentation in lines 90-91 and 102-103 of README.md also shows conflicting information - they suggest these should be simple names like "mySubnet" and "myVnet", but line 11 and 19 mention --subnet-id and --vnet-id, and the help text says these should be full Azure resource IDs.

Either:

  1. Change the option names to --subnet-id and --vnet-id to match the help text and internal variable names, OR
  2. Change the help text and documentation to clarify these are names (not IDs) and update the internal variable names accordingly

Based on the PR description mentioning "Network parameter simplification: Use --subnet-name and --vnet-name instead of complex JSON objects", it appears the intention is to use names, but the help text needs to be corrected.

Copilot uses AI. Check for mistakes.
return cls._args_schema

def _execute_operations(self):
Expand Down Expand Up @@ -242,26 +224,16 @@ def content(self):
typ=AAZObjectType,
typ_kwargs={"flags": {"required": True, "client_flatten": True}}
)
_builder.set_prop("identity", AAZIdentityObjectType)
_builder.set_prop("location", AAZStrType, ".location", typ_kwargs={"flags": {"required": True}})
_builder.set_prop("properties", AAZObjectType, typ_kwargs={"flags": {"client_flatten": True}})
_builder.set_prop("tags", AAZDictType, ".tags")

identity = _builder.get(".identity")
if identity is not None:
identity.set_prop("userAssigned", AAZListType, ".mi_user_assigned", typ_kwargs={"flags": {"action": "create"}})
identity.set_prop("systemAssigned", AAZStrType, ".mi_system_assigned", typ_kwargs={"flags": {"action": "create"}})

user_assigned = _builder.get(".identity.userAssigned")
if user_assigned is not None:
user_assigned.set_elements(AAZStrType, ".")

properties = _builder.get(".properties")
if properties is not None:
properties.set_prop("availabilityZone", AAZStrType, ".availability_zone", typ_kwargs={"flags": {"required": True}})
properties.set_prop("availabilityZone", AAZStrType, ".zone", typ_kwargs={"flags": {"required": True}})
properties.set_prop("provisionedBandwidthMbPerSec", AAZIntType, ".provisioned_bandwidth", typ_kwargs={"flags": {"required": True}})
properties.set_prop("reservationResourceId", AAZStrType, ".reservation_id", typ_kwargs={"flags": {"required": True}})
properties.set_prop("vnetInjection", AAZObjectType, ".vnet_injection", typ_kwargs={"flags": {"required": True}})
properties.set_prop("vnetInjection", AAZObjectType, ".", typ_kwargs={"flags": {"required": True}})
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The second parameter "." in the vnetInjection set_prop call is likely incorrect. Following the pattern used elsewhere in the codebase (e.g., line 228 for "properties", and similar patterns in other files), when setting an object type that is composed of multiple sub-fields rather than mapping to a single argument, the second parameter should be omitted entirely.

The vnetInjection object is built from subnet_id and vnet_id fields (lines 240-241), so this should probably be:
properties.set_prop("vnetInjection", AAZObjectType, typ_kwargs={"flags": {"required": True}})

Using "." as the second parameter would attempt to use the entire args context as the value, which doesn't make sense given that the actual values are set on lines 240-241.

Suggested change
properties.set_prop("vnetInjection", AAZObjectType, ".", typ_kwargs={"flags": {"required": True}})
properties.set_prop("vnetInjection", AAZObjectType, typ_kwargs={"flags": {"required": True}})

Copilot uses AI. Check for mistakes.

vnet_injection = _builder.get(".properties.vnetInjection")
if vnet_injection is not None:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@

@register_command(
"pscloud pool delete",
is_preview=True,
confirmation="Are you sure you want to perform this operation?",
)
class Delete(AAZCommand):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@

@register_command(
"pscloud pool get-avs-status",
is_preview=True,
)
class GetAvsStatus(AAZCommand):
"""Returns the status of the storage pool connection to AVS
Expand Down Expand Up @@ -49,7 +48,7 @@ def _build_arguments_schema(cls, *args, **kwargs):
required=True,
)
_args_schema.storage_pool_name = AAZStrArg(
options=["--storage-pool-name"],
options=["-n", "--name"],
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The parameter options only include ["-n", "--name"] without the "--storage-pool-name" alias. However, other commands in the same command group (_create.py line 52, _show.py line 51, _delete.py line 53, _update.py line 52) include all three options: ["-n", "--name", "--storage-pool-name"].

For consistency and backward compatibility, this should also include "--storage-pool-name" as an alias option, similar to the other commands.

Suggested change
options=["-n", "--name"],
options=["-n", "--name", "--storage-pool-name"],

Copilot uses AI. Check for mistakes.
help="Name of the storage pool",
required=True,
id_part="name",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@

@register_command(
"pscloud pool get-health-status",
is_preview=True,
)
class GetHealthStatus(AAZCommand):
"""Retrieve health metrics of a storage pool
Expand Down Expand Up @@ -49,7 +48,7 @@ def _build_arguments_schema(cls, *args, **kwargs):
required=True,
)
_args_schema.storage_pool_name = AAZStrArg(
options=["--storage-pool-name"],
options=["-n", "--name"],
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The parameter options only include ["-n", "--name"] without the "--storage-pool-name" alias. However, other commands in the same command group (_create.py line 52, _show.py line 51, _delete.py line 53, _update.py line 52) include all three options: ["-n", "--name", "--storage-pool-name"].

For consistency and backward compatibility, this should also include "--storage-pool-name" as an alias option, similar to the other commands.

Suggested change
options=["-n", "--name"],
options=["-n", "--name", "--storage-pool-name"],

Copilot uses AI. Check for mistakes.
help="Name of the storage pool",
required=True,
id_part="name",
Expand Down
1 change: 0 additions & 1 deletion src/pscloud/azext_pscloud/aaz/latest/pscloud/pool/_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@

@register_command(
"pscloud pool list",
is_preview=True,
)
class List(AAZCommand):
"""List storage pools by Azure subscription ID
Expand Down
1 change: 0 additions & 1 deletion src/pscloud/azext_pscloud/aaz/latest/pscloud/pool/_show.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@

@register_command(
"pscloud pool show",
is_preview=True,
)
class Show(AAZCommand):
"""Get a storage pool
Expand Down
30 changes: 0 additions & 30 deletions src/pscloud/azext_pscloud/aaz/latest/pscloud/pool/_update.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@

@register_command(
"pscloud pool update",
is_preview=True,
)
class Update(AAZCommand):
"""Update a storage pool
Expand Down Expand Up @@ -61,25 +60,6 @@ def _build_arguments_schema(cls, *args, **kwargs):
),
)

# define Arg Group "Identity"

_args_schema = cls._args_schema
_args_schema.mi_system_assigned = AAZStrArg(
options=["--system-assigned", "--mi-system-assigned"],
arg_group="Identity",
help="Set the system managed identity.",
blank="True",
)
_args_schema.mi_user_assigned = AAZListArg(
options=["--user-assigned", "--mi-user-assigned"],
arg_group="Identity",
help="Set the user managed identities.",
blank=[],
)

mi_user_assigned = cls._args_schema.mi_user_assigned
mi_user_assigned.Element = AAZStrArg()

# define Arg Group "Properties"

_args_schema = cls._args_schema
Expand Down Expand Up @@ -204,19 +184,9 @@ def content(self):
typ=AAZObjectType,
typ_kwargs={"flags": {"required": True, "client_flatten": True}}
)
_builder.set_prop("identity", AAZIdentityObjectType)
_builder.set_prop("properties", AAZObjectType, typ_kwargs={"flags": {"client_flatten": True}})
_builder.set_prop("tags", AAZDictType, ".tags")

identity = _builder.get(".identity")
if identity is not None:
identity.set_prop("userAssigned", AAZListType, ".mi_user_assigned", typ_kwargs={"flags": {"action": "create"}})
identity.set_prop("systemAssigned", AAZStrType, ".mi_system_assigned", typ_kwargs={"flags": {"action": "create"}})

user_assigned = _builder.get(".identity.userAssigned")
if user_assigned is not None:
user_assigned.set_elements(AAZStrType, ".")

properties = _builder.get(".properties")
if properties is not None:
properties.set_prop("provisionedBandwidthMbPerSec", AAZIntType, ".provisioned_bandwidth")
Expand Down
Loading
Loading