Skip to content

Commit 01448a9

Browse files
committed
Update the cluster stack command to be cluster-stack instead of hyp-cluster-stack (#219)
* Append UUID to resource name prefix to ensure uniqueness . --- Tested with unit tests and manual testing * Update the cluster stack command to be `cluster-stack` instead of `hyp-cluster-stack` * Fix
1 parent 383550c commit 01448a9

File tree

3 files changed

+47
-47
lines changed

3 files changed

+47
-47
lines changed

src/sagemaker/hyperpod/cli/commands/cluster_stack.py

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -39,25 +39,25 @@ def parse_status_list(ctx, param, value):
3939
raise click.BadParameter(f"Invalid list format. Use: \"['STATUS1', 'STATUS2']\". Error: {e}")
4040

4141

42-
@click.command("hyp-cluster-stack")
42+
@click.command("cluster-stack")
4343
@click.argument("config-file", required=True)
4444
@click.argument("stack-name", required=True)
4545
@click.option("--region", help="AWS region")
4646
@click.option("--debug", is_flag=True, help="Enable debug logging")
4747
def create_cluster_stack(config_file, region, debug):
4848
"""Create a new HyperPod cluster stack using the provided configuration.
49-
49+
5050
Creates a CloudFormation stack for a HyperPod cluster using settings from a YAML configuration file.
5151
The stack will provision all necessary AWS resources for the cluster.
52-
52+
5353
.. dropdown:: Usage Examples
5454
:open:
5555
5656
.. code-block:: bash
5757
5858
# Create cluster stack with config file
5959
hyp create hyp-cluster cluster-config.yaml my-stack-name --region us-west-2
60-
60+
6161
# Create with debug logging
6262
hyp create hyp-cluster cluster-config.yaml my-stack-name --debug
6363
"""
@@ -131,24 +131,24 @@ def create_cluster_stack_helper(config_file: str, region: Optional[str] = None,
131131
logger.exception("Detailed error information:")
132132
raise click.ClickException(str(e))
133133

134-
@click.command("hyp-cluster-stack")
134+
@click.command("cluster-stack")
135135
@click.argument("stack-name", required=True)
136136
@click.option("--region", help="AWS region")
137137
@click.option("--debug", is_flag=True, help="Enable debug logging")
138138
def describe_cluster_stack(stack_name: str, debug: bool, region: str) -> None:
139139
"""Describe the status of a HyperPod cluster stack.
140-
140+
141141
Shows detailed information about a CloudFormation stack including its current status,
142142
resources, and configuration parameters.
143-
143+
144144
.. dropdown:: Usage Examples
145145
:open:
146146
147147
.. code-block:: bash
148148
149149
# Describe a cluster stack
150150
hyp describe hyp-cluster my-stack-name
151-
151+
152152
# Describe with specific region
153153
hyp describe hyp-cluster my-stack-name --region us-west-2
154154
"""
@@ -206,26 +206,26 @@ def describe_cluster_stack(stack_name: str, debug: bool, region: str) -> None:
206206

207207
raise click.ClickException(str(e))
208208

209-
@click.command("hyp-cluster-stack")
209+
@click.command("cluster-stack")
210210
@click.option("--region", help="AWS region")
211211
@click.option("--debug", is_flag=True, help="Enable debug logging")
212212
@click.option("--status",
213213
callback=parse_status_list,
214214
help="Filter by stack status. Format: \"['CREATE_COMPLETE', 'UPDATE_COMPLETE']\"")
215215
def list_cluster_stacks(region, debug, status):
216216
"""List all HyperPod cluster stacks.
217-
217+
218218
Displays a summary of all CloudFormation stacks related to HyperPod clusters
219219
in the specified region or default region.
220-
220+
221221
.. dropdown:: Usage Examples
222222
:open:
223223
224224
.. code-block:: bash
225225
226226
# List all cluster stacks
227227
hyp list hyp-cluster
228-
228+
229229
# List stacks in specific region
230230
hyp list hyp-cluster --region us-east-1
231231
"""
@@ -276,15 +276,15 @@ def list_cluster_stacks(region, debug, status):
276276

277277
raise click.ClickException(str(e))
278278

279-
@click.command("hyp-cluster-stack")
279+
@click.command("cluster-stack")
280280
@click.argument("stack-name", required=True)
281281
@click.option("--debug", is_flag=True, help="Enable debug logging")
282282
def delete(stack_name: str, debug: bool) -> None:
283283
"""Delete a HyperPod cluster stack.
284-
284+
285285
Removes the specified CloudFormation stack and all associated AWS resources.
286286
This operation cannot be undone.
287-
287+
288288
.. dropdown:: Usage Examples
289289
:open:
290290
@@ -298,7 +298,7 @@ def delete(stack_name: str, debug: bool) -> None:
298298
logger.info(f"Deleting stack: {stack_name}")
299299
logger.info("This feature is not yet implemented.")
300300

301-
@click.command("hyp-cluster")
301+
@click.command("cluster")
302302
@click.option("--cluster-name", required=True, help="The name of the cluster to update")
303303
@click.option("--instance-groups", help="Instance Groups JSON string")
304304
@click.option("--instance-groups-to-delete", help="Instance Groups to delete JSON string")
@@ -313,18 +313,18 @@ def update_cluster(
313313
node_recovery: Optional[str],
314314
debug: bool) -> None:
315315
"""Update an existing HyperPod cluster configuration.
316-
316+
317317
Modifies cluster settings such as instance groups and node recovery policies.
318318
At least one update parameter must be provided.
319-
319+
320320
.. dropdown:: Usage Examples
321321
:open:
322322
323323
.. code-block:: bash
324324
325325
# Update cluster with new instance groups
326326
hyp update hyp-cluster --cluster-name my-cluster --instance-groups '{"group1": {...}}'
327-
327+
328328
# Update node recovery setting
329329
hyp update hyp-cluster --cluster-name my-cluster --node-recovery Automatic
330330
"""

src/sagemaker/hyperpod/cli/constants/init_constants.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
# 'template': KUBERNETES_PYTORCH_JOB_TEMPLATE,
3535
# 'type': "jinja"
3636
# },
37-
"hyp-cluster-stack": {
37+
"cluster-stack": {
3838
"schema_pkg": "hyperpod_cluster_stack_template",
3939
"schema_type": CFN,
4040
'template': CLOUDFORMATION_CLUSTER_CREATION_TEMPLATE,
@@ -66,7 +66,7 @@
6666
6767
Example:
6868
```bash
69-
hyp init hyp-cluster-stack
69+
hyp init cluster-stack
7070
```
7171
7272
This creates the following files in your current directory:
@@ -81,23 +81,23 @@
8181
You can specify a target directory for initialization:
8282
8383
```bash
84-
hyp init hyp-cluster-stack <directory>
84+
hyp init cluster-stack <directory>
8585
cd <directory>
8686
```
8787
8888
### Edge Cases
8989
9090
**Re-initializing the same template:**
9191
```
92-
hyp init hyp-cluster-stack
93-
⚠️ config.yaml already initialized as 'hyp-cluster-stack'.
92+
hyp init cluster-stack
93+
⚠️ config.yaml already initialized as 'cluster-stack'.
9494
Overwrite? [y/N]:
9595
```
9696
9797
**Initializing with a different template:**
9898
```
9999
hyp init hyp-custom-endpoint
100-
⚠️ Directory already initialized as 'hyp-cluster-stack'.
100+
⚠️ Directory already initialized as 'cluster-stack'.
101101
⚠️ It is highly unrecommended to initiate this directory with a different template.
102102
⚠️ Recommended path is create a new folder and then init with 'hyp-custom-endpoint'.
103103
If you insist, re-init as 'hyp-custom-endpoint' instead? [y/N]:
@@ -154,7 +154,7 @@
154154
155155
1. Initialize a new endpoint configuration:
156156
```bash
157-
hyp init hyp-cluster-stack
157+
hyp init cluster-stack
158158
```
159159
160160
2. Configure required parameters:
@@ -176,7 +176,7 @@
176176
177177
5. Check the status of your cluster stack:
178178
```bash
179-
hyp list hyp-cluster-stack
179+
hyp list cluster-stack
180180
```
181181
"""
182182

test/unit_tests/cli/test_cluster_stack.py

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ def test_create_cluster_stack_helper_success(self, mock_file, mock_exists, mock_
317317
# Setup mocks
318318
mock_exists.return_value = True
319319
mock_yaml_load.return_value = {
320-
'template': 'hyp-cluster-stack',
320+
'template': 'cluster-stack',
321321
'version': '1.0',
322322
'eks_cluster_name': 'test-cluster',
323323
'namespace': 'test-namespace'
@@ -375,7 +375,7 @@ def test_create_cluster_stack_helper_filters_template_fields(self, mock_file, mo
375375
# Setup mocks
376376
mock_exists.return_value = True
377377
mock_yaml_load.return_value = {
378-
'template': 'hyp-cluster-stack',
378+
'template': 'cluster-stack',
379379
'namespace': 'test-namespace',
380380
'version': '1.0',
381381
'eks_cluster_name': 'test-cluster',
@@ -409,7 +409,7 @@ def test_create_cluster_stack_helper_filters_none_values(self, mock_file, mock_e
409409
# Setup mocks
410410
mock_exists.return_value = True
411411
mock_yaml_load.return_value = {
412-
'template': 'hyp-cluster-stack',
412+
'template': 'cluster-stack',
413413
'eks_cluster_name': 'test-cluster',
414414
'optional_field': None,
415415
'required_field': 'value'
@@ -430,7 +430,7 @@ def test_create_cluster_stack_helper_filters_none_values(self, mock_file, mock_e
430430
call_args = mock_cluster_stack.call_args[1]
431431
assert 'optional_field' not in call_args
432432
assert 'required_field' in call_args
433-
433+
434434
@patch('sagemaker.hyperpod.cli.commands.cluster_stack.HpClusterStack')
435435
@patch('yaml.safe_load')
436436
@patch('os.path.exists')
@@ -440,42 +440,42 @@ def test_create_cluster_stack_helper_appends_uuid_to_resource_name_prefix(self,
440440
# Mock template methods
441441
mock_get_template.return_value = '{"Parameters": {}}'
442442
mock_read_text.return_value = 'Parameters: {}'
443-
443+
444444
# Setup mocks
445445
mock_exists.return_value = True
446446
original_prefix = 'hyperpod-cli-integ-test'
447447
mock_yaml_load.return_value = {
448-
'template': 'hyp-cluster-stack',
448+
'template': 'cluster-stack',
449449
'resource_name_prefix': original_prefix,
450450
'version': '1.0'
451451
}
452-
452+
453453
# Mock the stack instance and its create method to avoid AWS calls
454454
mock_stack_instance = Mock()
455455
mock_stack_instance.create.return_value = {'StackId': 'test-stack-id'}
456456
mock_cluster_stack.return_value = mock_stack_instance
457-
457+
458458
with patch('sagemaker.hyperpod.cli.commands.cluster_stack.logger') as mock_logger:
459459
from sagemaker.hyperpod.cli.commands.cluster_stack import create_cluster_stack_helper
460-
460+
461461
# Execute
462462
create_cluster_stack_helper('config.yaml', 'us-west-2', False)
463-
463+
464464
# Verify UUID was appended to resource_name_prefix
465465
call_args = mock_cluster_stack.call_args[1]
466466
modified_prefix = call_args['resource_name_prefix']
467-
467+
468468
# Check that the prefix starts with the original value
469469
assert modified_prefix.startswith(original_prefix + '-'), f"Expected prefix to start with '{original_prefix}-', got '{modified_prefix}'"
470-
470+
471471
# Check that exactly 4 characters were appended (plus the dash)
472472
assert len(modified_prefix) == len(original_prefix) + 5, f"Expected length {len(original_prefix) + 5}, got {len(modified_prefix)}"
473-
473+
474474
# Check that the appended part is alphanumeric (UUID format)
475475
uuid_part = modified_prefix[len(original_prefix) + 1:]
476476
assert len(uuid_part) == 4, f"UUID part should be 4 characters, got {len(uuid_part)}"
477477
assert uuid_part.replace('-', '').isalnum(), f"UUID part should be alphanumeric, got '{uuid_part}'"
478-
478+
479479
@patch('sagemaker.hyperpod.cli.commands.cluster_stack.HpClusterStack')
480480
@patch('yaml.safe_load')
481481
@patch('os.path.exists')
@@ -485,26 +485,26 @@ def test_create_cluster_stack_helper_handles_empty_resource_name_prefix(self, mo
485485
# Mock template methods
486486
mock_get_template.return_value = '{"Parameters": {}}'
487487
mock_read_text.return_value = 'Parameters: {}'
488-
488+
489489
# Setup mocks
490490
mock_exists.return_value = True
491491
mock_yaml_load.return_value = {
492-
'template': 'hyp-cluster-stack',
492+
'template': 'cluster-stack',
493493
'resource_name_prefix': '',
494494
'version': '1.0'
495495
}
496-
496+
497497
# Mock the stack instance and its create method to avoid AWS calls
498498
mock_stack_instance = Mock()
499499
mock_stack_instance.create.return_value = {'StackId': 'test-stack-id'}
500500
mock_cluster_stack.return_value = mock_stack_instance
501-
501+
502502
with patch('sagemaker.hyperpod.cli.commands.cluster_stack.logger') as mock_logger:
503503
from sagemaker.hyperpod.cli.commands.cluster_stack import create_cluster_stack_helper
504-
504+
505505
# Execute
506506
create_cluster_stack_helper('config.yaml', 'us-west-2', False)
507-
507+
508508
# Verify empty prefix is not modified
509509
call_args = mock_cluster_stack.call_args[1]
510510
assert call_args['resource_name_prefix'] == ''

0 commit comments

Comments
 (0)