Skip to content

Unable to scale in instances group instance_count to 0 #347

@Shellmode

Description

@Shellmode

When I set instance_count to 0

cluster_name="hyp-cluster"
hyp update cluster --cluster-name $cluster_name \
    --instance-groups '[{
        "instance_group_name": "xxx",
        "instance_type": "ml.g5.2xlarge",
        "instance_count": 0,
        "execution_role": "arn:aws:iam::123456789012:role/hyp-clusterExecRole",
        "life_cycle_config": {
            "source_s3_uri": "s3://hyp-bucket",
            "on_create": "on_create.sh"
        }
    }]'

Error message as following

INFO:sagemaker_core.main.resources:Updating cluster resource.
╭─────────────────────────────── Traceback (most recent call last) ────────────────────────────────╮
│ /Users/qruwang/pyenv/base/bin/hyp:7 in <module>                                                  │
│                                                                                                  │
│   4 if __name__ == '__main__':                                                                   │
│   5 │   if sys.argv[0].endswith('.exe'):                                                         │
│   6 │   │   sys.argv[0] = sys.argv[0][:-4]                                                       │
│ ❱ 7 │   sys.exit(cli())                                                                          │
│   8                                                                                              │
│                                                                                                  │
│ /Users/qruwang/pyenv/base/lib/python3.13/site-packages/click/core.py:1157 in __call__            │
│                                                                                                  │
│   1154 │                                                                                         │
│   1155 │   def __call__(self, *args: t.Any, **kwargs: t.Any) -> t.Any:                           │
│   1156 │   │   """Alias for :meth:`main`."""                                                     │
│ ❱ 1157 │   │   return self.main(*args, **kwargs)                                                 │
│   1158                                                                                           │
│   1159                                                                                           │
│   1160 class Command(BaseCommand):                                                               │
│                                                                                                  │
│ /Users/qruwang/pyenv/base/lib/python3.13/site-packages/click/core.py:1078 in main                │
│                                                                                                  │
│   1075 │   │   try:                                                                              │
│   1076 │   │   │   try:                                                                          │
│   1077 │   │   │   │   with self.make_context(prog_name, args, **extra) as ctx:                  │
│ ❱ 1078 │   │   │   │   │   rv = self.invoke(ctx)                                                 │
│   1079 │   │   │   │   │   if not standalone_mode:                                               │
│   1080 │   │   │   │   │   │   return rv                                                         │
│   1081 │   │   │   │   │   # it's not safe to `ctx.exit(rv)` here!                               │
│                                                                                                  │
│ /Users/qruwang/pyenv/base/lib/python3.13/site-packages/click/core.py:1688 in invoke              │
│                                                                                                  │
│   1685 │   │   │   │   super().invoke(ctx)                                                       │
│   1686 │   │   │   │   sub_ctx = cmd.make_context(cmd_name, args, parent=ctx)                    │
│   1687 │   │   │   │   with sub_ctx:                                                             │
│ ❱ 1688 │   │   │   │   │   return _process_result(sub_ctx.command.invoke(sub_ctx))               │
│   1689 │   │                                                                                     │
│   1690 │   │   # In chain mode we create the contexts step by step, but after the                │
│   1691 │   │   # base command has been invoked.  Because at that point we do not                 │
│                                                                                                  │
│ /Users/qruwang/pyenv/base/lib/python3.13/site-packages/click/core.py:1688 in invoke              │
│                                                                                                  │
│   1685 │   │   │   │   super().invoke(ctx)                                                       │
│   1686 │   │   │   │   sub_ctx = cmd.make_context(cmd_name, args, parent=ctx)                    │
│   1687 │   │   │   │   with sub_ctx:                                                             │
│ ❱ 1688 │   │   │   │   │   return _process_result(sub_ctx.command.invoke(sub_ctx))               │
│   1689 │   │                                                                                     │
│   1690 │   │   # In chain mode we create the contexts step by step, but after the                │
│   1691 │   │   # base command has been invoked.  Because at that point we do not                 │
│                                                                                                  │
│ /Users/qruwang/pyenv/base/lib/python3.13/site-packages/click/core.py:1434 in invoke              │
│                                                                                                  │
│   1431 │   │   │   echo(style(message, fg="red"), err=True)                                      │
│   1432 │   │                                                                                     │
│   1433 │   │   if self.callback is not None:                                                     │
│ ❱ 1434 │   │   │   return ctx.invoke(self.callback, **ctx.params)                                │
│   1435 │                                                                                         │
│   1436 │   def shell_complete(self, ctx: Context, incomplete: str) -> t.List["CompletionItem"]:  │
│   1437 │   │   """Return a list of completions for the incomplete value. Looks                   │
│                                                                                                  │
│ /Users/qruwang/pyenv/base/lib/python3.13/site-packages/click/core.py:783 in invoke               │
│                                                                                                  │
│    780 │   │                                                                                     │
│    781 │   │   with augment_usage_errors(__self):                                                │
│    782 │   │   │   with ctx:                                                                     │
│ ❱  783 │   │   │   │   return __callback(*args, **kwargs)                                        │
│    784 │                                                                                         │
│    785 │   def forward(                                                                          │
│    786 │   │   __self, __cmd: "Command", *args: t.Any, **kwargs: t.Any  # noqa: B902             │
│                                                                                                  │
│ /Users/qruwang/pyenv/base/lib/python3.13/site-packages/sagemaker/hyperpod/common/telemetry/telem │
│ etry_logging.py:179 in wrapper                                                                   │
│                                                                                                  │
│   176 │   │   │                                                                                  │
│   177 │   │   │   start = perf_counter()                                                         │
│   178 │   │   │   try:                                                                           │
│ ❱ 179 │   │   │   │   result = func(*args, **kwargs)                                             │
│   180 │   │   │   │   duration = round(perf_counter() - start, 2)                                │
│   181 │   │   │   │   extra += f"&x-latency={duration}"                                          │
│   182 │   │   │   │   _send_telemetry_request(                                                   │
│                                                                                                  │
│ /Users/qruwang/pyenv/base/lib/python3.13/site-packages/sagemaker/hyperpod/cli/commands/cluster_s │
│ tack.py:389 in update_cluster                                                                    │
│                                                                                                  │
│   386 │   │   update_params['node_recovery'] = node_recovery                                     │
│   387 │                                                                                          │
│   388 │   click.secho(f"Update Params: {update_params}")                                         │
│ ❱ 389 │   cluster.update(**update_params)                                                        │
│   390 │                                                                                          │
│   391 │   logger.info("Cluster has been updated")                                                │
│   392 │   click.secho(f"Cluster {cluster_name} has been updated")                                │
│                                                                                                  │
│ /Users/qruwang/pyenv/base/lib/python3.13/site-packages/sagemaker_core/main/resources.py:3278 in  │
│ wrapper                                                                                          │
│                                                                                                  │
│    3275 │   │   │   │   },                                                                       │
│    3276 │   │   │   │   "cluster_role": {"type": "string"},                                      │
│    3277 │   │   │   }                                                                            │
│ ❱  3278 │   │   │   return create_func(                                                          │
│    3279 │   │   │   │   *args,                                                                   │
│    3280 │   │   │   │   **Base.get_updated_kwargs_with_configured_attributes(                    │
│    3281 │   │   │   │   │   config_schema_for_resource, "Cluster", **kwargs                      │
│                                                                                                  │
│ /Users/qruwang/pyenv/base/lib/python3.13/site-packages/sagemaker_core/main/resources.py:140 in   │
│ wrapper                                                                                          │
│                                                                                                  │
│     137 │   │   @functools.wraps(func)                                                           │
│     138 │   │   def wrapper(*args, **kwargs):                                                    │
│     139 │   │   │   config = dict(arbitrary_types_allowed=True)                                  │
│ ❱   140 │   │   │   return validate_call(config=config)(func)(*args, **kwargs)                   │
│     141 │   │                                                                                    │
│     142 │   │   return wrapper                                                                   │
│     143                                                                                          │
│                                                                                                  │
│ /Users/qruwang/pyenv/base/lib/python3.13/site-packages/pydantic/_internal/_validate_call.py:39   │
│ in wrapper_function                                                                              │
│                                                                                                  │
│    36 │   │                                                                                      │
│    37 │   │   @functools.wraps(wrapped)                                                          │
│    38 │   │   def wrapper_function(*args, **kwargs):                                             │
│ ❱  39 │   │   │   return wrapper(*args, **kwargs)                                                │
│    40 │                                                                                          │
│    41 │   # We need to manually update this because `partial` object has no `__name__` and `__   │
│    42 │   wrapper_function.__name__ = extract_function_name(wrapped)                             │
│                                                                                                  │
│ /Users/qruwang/pyenv/base/lib/python3.13/site-packages/pydantic/_internal/_validate_call.py:136  │
│ in __call__                                                                                      │
│                                                                                                  │
│   133 │   │   if not self.__pydantic_complete__:                                                 │
│   134 │   │   │   self._create_validators()                                                      │
│   135 │   │                                                                                      │
│ ❱ 136 │   │   res = self.__pydantic_validator__.validate_python(pydantic_core.ArgsKwargs(args,   │
│   137 │   │   if self.__return_pydantic_validator__:                                             │
│   138 │   │   │   return self.__return_pydantic_validator__(res)                                 │
│   139 │   │   else:                                                                              │
│                                                                                                  │
│ /Users/qruwang/pyenv/base/lib/python3.13/site-packages/sagemaker_core/main/resources.py:3527 in  │
│ update                                                                                           │
│                                                                                                  │
│    3524 │   │   logger.debug(f"Serialized input request: {operation_input_args}")                │
│    3525 │   │                                                                                    │
│    3526 │   │   # create the resource                                                            │
│ ❱  3527 │   │   response = client.update_cluster(**operation_input_args)                         │
│    3528 │   │   logger.debug(f"Response: {response}")                                            │
│    3529 │   │   self.refresh()                                                                   │
│    3530                                                                                          │
│                                                                                                  │
│ /Users/qruwang/pyenv/base/lib/python3.13/site-packages/botocore/client.py:602 in _api_call       │
│                                                                                                  │
│    599 │   │   │   │   │   f"{py_operation_name}() only accepts keyword arguments."              │
│    600 │   │   │   │   )                                                                         │
│    601 │   │   │   # The "self" in this scope is referring to the BaseClient.                    │
│ ❱  602 │   │   │   return self._make_api_call(operation_name, kwargs)                            │
│    603 │   │                                                                                     │
│    604 │   │   _api_call.__name__ = str(py_operation_name)                                       │
│    605                                                                                           │
│                                                                                                  │
│ /Users/qruwang/pyenv/base/lib/python3.13/site-packages/botocore/context.py:123 in wrapper        │
│                                                                                                  │
│   120 │   │   │   with start_as_current_context():                                               │
│   121 │   │   │   │   if hook:                                                                   │
│   122 │   │   │   │   │   hook()                                                                 │
│ ❱ 123 │   │   │   │   return func(*args, **kwargs)                                               │
│   124 │   │                                                                                      │
│   125 │   │   return wrapper                                                                     │
│   126                                                                                            │
│                                                                                                  │
│ /Users/qruwang/pyenv/base/lib/python3.13/site-packages/botocore/client.py:1035 in _make_api_call │
│                                                                                                  │
│   1032 │   │   │   # Pass arbitrary endpoint info with the Request                               │
│   1033 │   │   │   # for use during construction.                                                │
│   1034 │   │   │   request_context['endpoint_properties'] = properties                           │
│ ❱ 1035 │   │   request_dict = self._convert_to_request_dict(                                     │
│   1036 │   │   │   api_params=api_params,                                                        │
│   1037 │   │   │   operation_model=operation_model,                                              │
│   1038 │   │   │   endpoint_url=endpoint_url,                                                    │
│                                                                                                  │
│ /Users/qruwang/pyenv/base/lib/python3.13/site-packages/botocore/client.py:1102 in                │
│ _convert_to_request_dict                                                                         │
│                                                                                                  │
│   1099 │   │   headers=None,                                                                     │
│   1100 │   │   set_user_agent_header=True,                                                       │
│   1101 │   ):                                                                                    │
│ ❱ 1102 │   │   request_dict = self._serializer.serialize_to_request(                             │
│   1103 │   │   │   api_params, operation_model                                                   │
│   1104 │   │   )                                                                                 │
│   1105 │   │   if not self._client_config.inject_host_prefix:                                    │
│                                                                                                  │
│ /Users/qruwang/pyenv/base/lib/python3.13/site-packages/botocore/validate.py:381 in               │
│ serialize_to_request                                                                             │
│                                                                                                  │
│   378 │   │   │   │   parameters, operation_model.input_shape                                    │
│   379 │   │   │   )                                                                              │
│   380 │   │   │   if report.has_errors():                                                        │
│ ❱ 381 │   │   │   │   raise ParamValidationError(report=report.generate_report())                │
│   382 │   │   return self._serializer.serialize_to_request(                                      │
│   383 │   │   │   parameters, operation_model                                                    │
│   384 │   │   )                                                                                  │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
ParamValidationError: Parameter validation failed:
Missing required parameter in InstanceGroups[0]: "InstanceCount"

I can only set instance_count on console

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions