Skip to content

Commit 7524b60

Browse files
Aman-Jain-14Aman JainCopilot
authored
Add amlfs expansion module and CRUD scenario tests (#9751)
* Add amlfs expansion module and CRUD scenario tests Add expansion job commands (create, delete, list, show, update, wait) for Azure Managed Lustre Filesystem storage capacity expansion using API version 2026-01-01. Include full CRUD scenario test with NAT gateway setup for private subnet compliance. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address PR review comments on test_expansion_job.py - Add 'az' prefix to helper method self.cmd() calls - Rewrite wait helpers to assert on failure/timeout with descriptive messages - Use order-independent JMESPath filter for list assertions Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add NAT gateway subnet setup to import/auto-export/auto-import tests Add the same private subnet with NAT gateway configuration used in expansion job tests to the import, auto-export, and auto-import test files for policy compliance with default outbound access restrictions. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add NAT gateway subnet setup to test_amlfs Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Re-record test cassettes with NAT gateway subnet setup Update VCR recordings for test_amlfs, test_import_job_crud, test_auto_export_job_crud, and test_auto_import_job_crud to reflect the NAT gateway subnet configuration changes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Aman Jain <amajai@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 2b99cb7 commit 7524b60

20 files changed

+21631
-4428
lines changed

src/amlfs/HISTORY.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
Release History
44
===============
55

6+
1.3.0
7+
+++++
8+
Added: az amlfs expansion create/update/list/show/delete commands for managing AMLFS expansion jobs. This helps the user manage the storage capacity expansion of their AMLFS instance as their data grows.
9+
610
1.2.0
711
+++++
812
Added: az amlfs auto-import create/update/list/show/delete commands for automatically importing data from Blob Storage to AMLFS
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# --------------------------------------------------------------------------------------------
2+
# Copyright (c) Microsoft Corporation. All rights reserved.
3+
# Licensed under the MIT License. See License.txt in the project root for license information.
4+
#
5+
# Code generated by aaz-dev-tools
6+
# --------------------------------------------------------------------------------------------
7+
8+
# pylint: skip-file
9+
# flake8: noqa
10+
11+
from azure.cli.core.aaz import *
12+
13+
14+
@register_command_group(
15+
"amlfs expansion",
16+
)
17+
class __CMDGroup(AAZCommandGroup):
18+
"""Manage Expansion
19+
"""
20+
pass
21+
22+
23+
__all__ = ["__CMDGroup"]
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# --------------------------------------------------------------------------------------------
2+
# Copyright (c) Microsoft Corporation. All rights reserved.
3+
# Licensed under the MIT License. See License.txt in the project root for license information.
4+
#
5+
# Code generated by aaz-dev-tools
6+
# --------------------------------------------------------------------------------------------
7+
8+
# pylint: skip-file
9+
# flake8: noqa
10+
11+
from .__cmd_group import *
12+
from ._create import *
13+
from ._delete import *
14+
from ._list import *
15+
from ._show import *
16+
from ._update import *
17+
from ._wait import *
Lines changed: 332 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,332 @@
1+
# --------------------------------------------------------------------------------------------
2+
# Copyright (c) Microsoft Corporation. All rights reserved.
3+
# Licensed under the MIT License. See License.txt in the project root for license information.
4+
#
5+
# Code generated by aaz-dev-tools
6+
# --------------------------------------------------------------------------------------------
7+
8+
# pylint: skip-file
9+
# flake8: noqa
10+
11+
from azure.cli.core.aaz import *
12+
13+
14+
@register_command(
15+
"amlfs expansion create",
16+
)
17+
class Create(AAZCommand):
18+
"""Increase filesystem storage capacity.
19+
20+
:example: expansionJobs_CreateOrUpdate
21+
az amlfs expansion create --resource-group scgroup --aml-filesystem-name fs1 --expansion-job-name expansionjob1 --tags "{Dept:ContosoAds}" --location eastus --new-storage-capacity 16.0
22+
"""
23+
24+
_aaz_info = {
25+
"version": "2026-01-01",
26+
"resources": [
27+
["mgmt-plane", "/subscriptions/{}/resourcegroups/{}/providers/microsoft.storagecache/amlfilesystems/{}/expansionjobs/{}", "2026-01-01"],
28+
]
29+
}
30+
31+
AZ_SUPPORT_NO_WAIT = True
32+
33+
def _handler(self, command_args):
34+
super()._handler(command_args)
35+
return self.build_lro_poller(self._execute_operations, self._output)
36+
37+
_args_schema = None
38+
39+
@classmethod
40+
def _build_arguments_schema(cls, *args, **kwargs):
41+
if cls._args_schema is not None:
42+
return cls._args_schema
43+
cls._args_schema = super()._build_arguments_schema(*args, **kwargs)
44+
45+
# define Arg Group ""
46+
47+
_args_schema = cls._args_schema
48+
_args_schema.aml_filesystem_name = AAZStrArg(
49+
options=["--aml-filesystem-name"],
50+
help="Name for the AML file system. Allows alphanumerics, underscores, and hyphens. Start and end with alphanumeric.",
51+
required=True,
52+
fmt=AAZStrArgFormat(
53+
pattern="^[0-9a-zA-Z][-0-9a-zA-Z_]{0,78}[0-9a-zA-Z]$",
54+
max_length=80,
55+
min_length=2,
56+
),
57+
)
58+
_args_schema.expansion_job_name = AAZStrArg(
59+
options=["-n", "--name", "--expansion-job-name"],
60+
help="Name for the expansion job. Allows alphanumerics, underscores, and hyphens. Start and end with alphanumeric.",
61+
required=True,
62+
fmt=AAZStrArgFormat(
63+
pattern="^[0-9a-zA-Z][-0-9a-zA-Z_]{0,78}[0-9a-zA-Z]$",
64+
max_length=80,
65+
min_length=2,
66+
),
67+
)
68+
_args_schema.resource_group = AAZResourceGroupNameArg(
69+
required=True,
70+
)
71+
72+
# define Arg Group "ExpansionJob"
73+
74+
_args_schema = cls._args_schema
75+
_args_schema.location = AAZResourceLocationArg(
76+
arg_group="ExpansionJob",
77+
help="The geo-location where the resource lives",
78+
required=True,
79+
fmt=AAZResourceLocationArgFormat(
80+
resource_group_arg="resource_group",
81+
),
82+
)
83+
_args_schema.tags = AAZDictArg(
84+
options=["--tags"],
85+
arg_group="ExpansionJob",
86+
help="Resource tags.",
87+
)
88+
89+
tags = cls._args_schema.tags
90+
tags.Element = AAZStrArg()
91+
92+
# define Arg Group "Properties"
93+
94+
_args_schema = cls._args_schema
95+
_args_schema.new_storage_capacity = AAZFloatArg(
96+
options=["--size", "--new-storage-capacity"],
97+
arg_group="Properties",
98+
help="The new storage capacity in TiB for the AML file system after expansion. This must be a multiple of the Sku step size, and greater than the current storage capacity of the AML file system.",
99+
)
100+
return cls._args_schema
101+
102+
def _execute_operations(self):
103+
self.pre_operations()
104+
yield self.ExpansionJobsCreateOrUpdate(ctx=self.ctx)()
105+
self.post_operations()
106+
107+
@register_callback
108+
def pre_operations(self):
109+
pass
110+
111+
@register_callback
112+
def post_operations(self):
113+
pass
114+
115+
def _output(self, *args, **kwargs):
116+
result = self.deserialize_output(self.ctx.vars.instance, client_flatten=True)
117+
return result
118+
119+
class ExpansionJobsCreateOrUpdate(AAZHttpOperation):
120+
CLIENT_TYPE = "MgmtClient"
121+
122+
def __call__(self, *args, **kwargs):
123+
request = self.make_request()
124+
session = self.client.send_request(request=request, stream=False, **kwargs)
125+
if session.http_response.status_code in [202]:
126+
return self.client.build_lro_polling(
127+
self.ctx.args.no_wait,
128+
session,
129+
self.on_200_201,
130+
self.on_error,
131+
lro_options={"final-state-via": "azure-async-operation"},
132+
path_format_arguments=self.url_parameters,
133+
)
134+
if session.http_response.status_code in [200, 201]:
135+
return self.client.build_lro_polling(
136+
self.ctx.args.no_wait,
137+
session,
138+
self.on_200_201,
139+
self.on_error,
140+
lro_options={"final-state-via": "azure-async-operation"},
141+
path_format_arguments=self.url_parameters,
142+
)
143+
144+
return self.on_error(session.http_response)
145+
146+
@property
147+
def url(self):
148+
return self.client.format_url(
149+
"/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.StorageCache/amlFilesystems/{amlFilesystemName}/expansionJobs/{expansionJobName}",
150+
**self.url_parameters
151+
)
152+
153+
@property
154+
def method(self):
155+
return "PUT"
156+
157+
@property
158+
def error_format(self):
159+
return "MgmtErrorFormat"
160+
161+
@property
162+
def url_parameters(self):
163+
parameters = {
164+
**self.serialize_url_param(
165+
"amlFilesystemName", self.ctx.args.aml_filesystem_name,
166+
required=True,
167+
),
168+
**self.serialize_url_param(
169+
"expansionJobName", self.ctx.args.expansion_job_name,
170+
required=True,
171+
),
172+
**self.serialize_url_param(
173+
"resourceGroupName", self.ctx.args.resource_group,
174+
required=True,
175+
),
176+
**self.serialize_url_param(
177+
"subscriptionId", self.ctx.subscription_id,
178+
required=True,
179+
),
180+
}
181+
return parameters
182+
183+
@property
184+
def query_parameters(self):
185+
parameters = {
186+
**self.serialize_query_param(
187+
"api-version", "2026-01-01",
188+
required=True,
189+
),
190+
}
191+
return parameters
192+
193+
@property
194+
def header_parameters(self):
195+
parameters = {
196+
**self.serialize_header_param(
197+
"Content-Type", "application/json",
198+
),
199+
**self.serialize_header_param(
200+
"Accept", "application/json",
201+
),
202+
}
203+
return parameters
204+
205+
@property
206+
def content(self):
207+
_content_value, _builder = self.new_content_builder(
208+
self.ctx.args,
209+
typ=AAZObjectType,
210+
typ_kwargs={"flags": {"required": True, "client_flatten": True}}
211+
)
212+
_builder.set_prop("location", AAZStrType, ".location", typ_kwargs={"flags": {"required": True}})
213+
_builder.set_prop("properties", AAZObjectType, typ_kwargs={"flags": {"client_flatten": True}})
214+
_builder.set_prop("tags", AAZDictType, ".tags")
215+
216+
properties = _builder.get(".properties")
217+
if properties is not None:
218+
properties.set_prop("newStorageCapacityTiB", AAZFloatType, ".new_storage_capacity")
219+
220+
tags = _builder.get(".tags")
221+
if tags is not None:
222+
tags.set_elements(AAZStrType, ".")
223+
224+
return self.serialize_content(_content_value)
225+
226+
def on_200_201(self, session):
227+
data = self.deserialize_http_content(session)
228+
self.ctx.set_var(
229+
"instance",
230+
data,
231+
schema_builder=self._build_schema_on_200_201
232+
)
233+
234+
_schema_on_200_201 = None
235+
236+
@classmethod
237+
def _build_schema_on_200_201(cls):
238+
if cls._schema_on_200_201 is not None:
239+
return cls._schema_on_200_201
240+
241+
cls._schema_on_200_201 = AAZObjectType()
242+
243+
_schema_on_200_201 = cls._schema_on_200_201
244+
_schema_on_200_201.id = AAZStrType(
245+
flags={"read_only": True},
246+
)
247+
_schema_on_200_201.location = AAZStrType(
248+
flags={"required": True},
249+
)
250+
_schema_on_200_201.name = AAZStrType(
251+
flags={"read_only": True},
252+
)
253+
_schema_on_200_201.properties = AAZObjectType(
254+
flags={"client_flatten": True},
255+
)
256+
_schema_on_200_201.system_data = AAZObjectType(
257+
serialized_name="systemData",
258+
flags={"read_only": True},
259+
)
260+
_schema_on_200_201.tags = AAZDictType()
261+
_schema_on_200_201.type = AAZStrType(
262+
flags={"read_only": True},
263+
)
264+
265+
properties = cls._schema_on_200_201.properties
266+
properties.new_storage_capacity_ti_b = AAZFloatType(
267+
serialized_name="newStorageCapacityTiB",
268+
)
269+
properties.provisioning_state = AAZStrType(
270+
serialized_name="provisioningState",
271+
flags={"read_only": True},
272+
)
273+
properties.status = AAZObjectType(
274+
flags={"client_flatten": True, "read_only": True},
275+
)
276+
277+
status = cls._schema_on_200_201.properties.status
278+
status.completion_time_utc = AAZStrType(
279+
serialized_name="completionTimeUTC",
280+
flags={"read_only": True},
281+
)
282+
status.percent_complete = AAZFloatType(
283+
serialized_name="percentComplete",
284+
flags={"read_only": True},
285+
)
286+
status.start_time_utc = AAZStrType(
287+
serialized_name="startTimeUTC",
288+
flags={"read_only": True},
289+
)
290+
status.state = AAZStrType(
291+
flags={"read_only": True},
292+
)
293+
status.status_code = AAZStrType(
294+
serialized_name="statusCode",
295+
flags={"read_only": True},
296+
)
297+
status.status_message = AAZStrType(
298+
serialized_name="statusMessage",
299+
flags={"read_only": True},
300+
)
301+
302+
system_data = cls._schema_on_200_201.system_data
303+
system_data.created_at = AAZStrType(
304+
serialized_name="createdAt",
305+
)
306+
system_data.created_by = AAZStrType(
307+
serialized_name="createdBy",
308+
)
309+
system_data.created_by_type = AAZStrType(
310+
serialized_name="createdByType",
311+
)
312+
system_data.last_modified_at = AAZStrType(
313+
serialized_name="lastModifiedAt",
314+
)
315+
system_data.last_modified_by = AAZStrType(
316+
serialized_name="lastModifiedBy",
317+
)
318+
system_data.last_modified_by_type = AAZStrType(
319+
serialized_name="lastModifiedByType",
320+
)
321+
322+
tags = cls._schema_on_200_201.tags
323+
tags.Element = AAZStrType()
324+
325+
return cls._schema_on_200_201
326+
327+
328+
class _CreateHelper:
329+
"""Helper class for Create"""
330+
331+
332+
__all__ = ["Create"]

0 commit comments

Comments
 (0)