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
70 changes: 42 additions & 28 deletions lisa/microsoft/testsuites/xfstests/xfstesting.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# Licensed under the MIT license.
import string
from pathlib import Path
from typing import Any, Dict, Union, cast
from typing import Any, Dict, Optional, Union, cast

from microsoft.testsuites.xfstests.xfstests import Xfstests

Expand Down Expand Up @@ -112,26 +112,56 @@ def _prepare_data_disk(
node.execute(f"mkdir {mount_point}", sudo=True)


# Updates as of march 2025.
# Default premium SKU will be used for file share creation.
# This will ensure SMB multi channel is enabled by default
# Updates as of December 2025.
# Default to Provisioned v2 (PV2) billing model for file share creation.
# PV2 allows independent provisioning of storage, IOPS, and throughput.
# PV2 supports smaller minimum quota (32 GiB vs 100 GiB for PV1).
# PV1 fallback is available via use_pv1_model=True for regions without PV2.
# SMB multi channel is enabled by default with premium SKUs.
def _deploy_azure_file_share(
node: Node,
environment: Environment,
names: Dict[str, str],
azure_file_share: Union[AzureFileShare, Nfs],
allow_shared_key_access: bool = True,
enable_private_endpoint: bool = True,
storage_account_sku: str = "Premium_LRS",
storage_account_sku: str = "PremiumV2_LRS",
storage_account_kind: str = "FileStorage",
file_share_quota_in_gb: int = 100,
file_share_quota_in_gb: int = 32,
provisioned_iops: Optional[int] = None,
provisioned_bandwidth_mibps: Optional[int] = None,
use_pv1_model: bool = False,
) -> Dict[str, str]:
"""
About: This method will provision azure file shares on a new // existing
storage account.
About: This method will provision azure file shares on a new or existing
storage account using the Provisioned v2 (PV2) billing model by default.

PV2 Billing Model (default):
- SKU: PremiumV2_LRS (SSD) or StandardV2_LRS (HDD)
- Minimum quota: 32 GiB
- Independent IOPS/throughput provisioning
- More cost-effective for testing workloads

PV1 Billing Model (legacy, use_pv1_model=True):
- SKU: Premium_LRS (SSD)
- Minimum quota: 100 GiB
- IOPS/throughput computed from storage size
- Use for regions where PV2 is not available

Args:
provisioned_iops: Optional IOPS for PV2 (None = use Azure defaults)
provisioned_bandwidth_mibps: Optional throughput for PV2 (None = defaults)
use_pv1_model: Set True to use legacy PV1 billing model

Returns: Dict[str, str] - A dictionary containing the file share names
and their respective URLs.
"""
# Handle PV1 fallback - override SKU and quota for compatibility
if use_pv1_model:
storage_account_sku = "Premium_LRS"
file_share_quota_in_gb = max(file_share_quota_in_gb, 100) # PV1 minimum
provisioned_iops = None # PV1 doesn't support explicit IOPS
provisioned_bandwidth_mibps = None # PV1 doesn't support explicit throughput
if isinstance(azure_file_share, AzureFileShare):
fs_url_dict: Dict[str, str] = azure_file_share.create_file_share(
file_share_names=list(names.values()),
Expand All @@ -141,6 +171,8 @@ def _deploy_azure_file_share(
allow_shared_key_access=allow_shared_key_access,
enable_private_endpoint=enable_private_endpoint,
quota_in_gb=file_share_quota_in_gb,
provisioned_iops=provisioned_iops,
provisioned_bandwidth_mibps=provisioned_bandwidth_mibps,
)
test_folders_share_dict: Dict[str, str] = {}
for key, value in names.items():
Expand Down Expand Up @@ -200,30 +232,10 @@ class Xfstesting(TestSuite):
+ " generic/680"
)

# def before_case(self, log: Logger, **kwargs: Any) -> None:
# node = kwargs["node"]
# if isinstance(node.os, Oracle) and (node.os.information.version <= "9.0.0"):
# self.excluded_tests = self.excluded_tests + " btrfs/299"

def before_case(self, log: Logger, **kwargs: Any) -> None:
global _default_smb_mount, _default_smb_excluded_tests
global _default_smb_testcases, _scratch_folder, _test_folder

node = kwargs["node"]
if isinstance(node.os, Oracle) and (node.os.information.version <= "9.0.0"):
self.excluded_tests = self.excluded_tests + " btrfs/299"
# check for user provided SMB mount options, excluded and included test cases
# for azure file share
variables: Dict[str, Any] = kwargs["variables"]
# check for overrides. pass variables with property case_visible: True
# in runbook
_default_smb_mount = variables.get("smb_mount_opts", _default_smb_mount)
_default_smb_excluded_tests = variables.get(
"smb_excluded_tests", _default_smb_excluded_tests
)
_default_smb_testcases = variables.get("smb_testcases", _default_smb_testcases)
_scratch_folder = variables.get("scratch_folder", _scratch_folder)
_test_folder = variables.get("test_folder", _test_folder)

@TestCaseMetadata(
description="""
Expand Down Expand Up @@ -615,6 +627,8 @@ def verify_azure_file_share(
_scratch_folder: scratch_name,
},
azure_file_share=azure_file_share,
provisioned_bandwidth_mibps=110,
provisioned_iops=3110,
)
# Get credential file path from the feature (uses storage account name)
mount_opts = (
Expand Down
32 changes: 27 additions & 5 deletions lisa/sut_orchestrator/azure/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -2247,9 +2247,22 @@ def get_or_create_file_share(
log: Logger,
protocols: str = "SMB",
quota_in_gb: int = 100,
provisioned_iops: Optional[int] = None,
provisioned_bandwidth_mibps: Optional[int] = None,
) -> str:
"""
Create an Azure Storage file share if it does not exist.

For Provisioned v2 (PV2) billing model, you can optionally specify:
- provisioned_iops: The provisioned IOPS for the share (PV2 only)
- provisioned_bandwidth_mibps: The provisioned throughput in MiB/s (PV2 only)

If these are not specified, Azure will use default recommendations based
on the provisioned storage size.

PV2 requires storage account SKU: PremiumV2_LRS, PremiumV2_ZRS,
StandardV2_LRS, StandardV2_ZRS, StandardV2_GRS, or StandardV2_GZRS.
PV2 minimum quota is 32 GiB (vs 100 GiB for PV1).
"""
share_service_client = get_share_service_client(
credential,
Expand All @@ -2261,11 +2274,20 @@ def get_or_create_file_share(
all_shares = list(share_service_client.list_shares())
if file_share_name not in (x.name for x in all_shares):
log.debug(f"creating file share {file_share_name} with protocols {protocols}")
share_service_client.create_share(
file_share_name,
protocols=protocols,
quota=quota_in_gb,
)
# Build kwargs for create_share - only include PV2 params if specified
create_kwargs: Dict[str, Any] = {
"protocols": protocols,
"quota": quota_in_gb,
}
# PV2-specific parameters (requires API version 2025-01-05+)
# These are only valid for PV2 storage accounts (PremiumV2_*, StandardV2_*)
if provisioned_iops is not None:
create_kwargs["provisioned_iops"] = provisioned_iops
log.debug(f" provisioned_iops: {provisioned_iops}")
if provisioned_bandwidth_mibps is not None:
create_kwargs["provisioned_bandwidth_mibps"] = provisioned_bandwidth_mibps
log.debug(f" provisioned_bandwidth_mibps: {provisioned_bandwidth_mibps}")
share_service_client.create_share(file_share_name, **create_kwargs)
return str("//" + share_service_client.primary_hostname + "/" + file_share_name)


Expand Down
4 changes: 4 additions & 0 deletions lisa/sut_orchestrator/azure/features.py
Original file line number Diff line number Diff line change
Expand Up @@ -3812,6 +3812,8 @@ def create_file_share(
enable_https_traffic_only: bool = True,
enable_private_endpoint: bool = False,
quota_in_gb: int = 100,
provisioned_iops: Optional[int] = None,
provisioned_bandwidth_mibps: Optional[int] = None,
) -> Dict[str, str]:
platform: AzurePlatform = self._platform # type: ignore
information = environment.get_information()
Expand Down Expand Up @@ -3850,6 +3852,8 @@ def create_file_share(
resource_group_name=resource_group_name,
log=self._log,
quota_in_gb=quota_in_gb,
provisioned_iops=provisioned_iops,
provisioned_bandwidth_mibps=provisioned_bandwidth_mibps,
)
# Create file private endpoint, always after all shares have been created
# There is a known issue in API preventing access to data plane
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ azure = [
"azure-mgmt-serialconsole ~= 1.0.0",
"azure-mgmt-storage ~= 21.2.1",
"azure-storage-blob ~= 12.23.0",
"azure-storage-file-share ~= 12.18.0",
"azure-storage-file-share ~= 12.20.0",
"azure-keyvault-secrets ~= 4.7.0",
"azure-keyvault-certificates ~= 4.7.0",
"msrestazure ~= 0.6.4",
Expand Down
Loading