anyscale 0.26.69__py3-none-any.whl → 0.26.70__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. anyscale/_private/anyscale_client/anyscale_client.py +67 -1
  2. anyscale/_private/anyscale_client/common.py +20 -1
  3. anyscale/_private/anyscale_client/fake_anyscale_client.py +77 -10
  4. anyscale/client/README.md +14 -4
  5. anyscale/client/openapi_client/__init__.py +11 -4
  6. anyscale/client/openapi_client/api/default_api.py +462 -23
  7. anyscale/client/openapi_client/models/__init__.py +11 -4
  8. anyscale/client/openapi_client/models/api_key_info.py +29 -3
  9. anyscale/client/openapi_client/models/apply_autoscaling_config_update_model.py +350 -0
  10. anyscale/client/openapi_client/models/apply_production_service_multi_version_v2_model.py +207 -0
  11. anyscale/client/openapi_client/models/apply_production_service_v2_model.py +31 -3
  12. anyscale/client/openapi_client/models/baseimagesenum.py +70 -1
  13. anyscale/client/openapi_client/models/cloud_data_bucket_file_type.py +2 -1
  14. anyscale/client/openapi_client/models/{oauthconnectionresponse_response.py → clouddeployment_response.py} +11 -11
  15. anyscale/client/openapi_client/models/create_experimental_workspace.py +29 -1
  16. anyscale/client/openapi_client/models/create_workspace_from_template.py +29 -1
  17. anyscale/client/openapi_client/models/create_workspace_template_version.py +31 -3
  18. anyscale/client/openapi_client/models/decorated_list_service_api_model.py +58 -1
  19. anyscale/client/openapi_client/models/decorated_production_service_v2_api_model.py +60 -3
  20. anyscale/client/openapi_client/models/decorated_service_event_api_model.py +3 -3
  21. anyscale/client/openapi_client/models/describe_machine_pool_machines_filters.py +33 -5
  22. anyscale/client/openapi_client/models/describe_machine_pool_workloads_filters.py +33 -5
  23. anyscale/client/openapi_client/models/{service_event_level.py → entity_type.py} +9 -9
  24. anyscale/client/openapi_client/models/event_level.py +2 -1
  25. anyscale/client/openapi_client/models/job_event_fields.py +206 -0
  26. anyscale/client/openapi_client/models/machine_type_partition_filter.py +152 -0
  27. anyscale/client/openapi_client/models/partition_info.py +30 -1
  28. anyscale/client/openapi_client/models/production_job_event.py +3 -3
  29. anyscale/client/openapi_client/models/rollout_strategy.py +2 -1
  30. anyscale/client/openapi_client/models/service_event_fields.py +318 -0
  31. anyscale/client/openapi_client/models/supportedbaseimagesenum.py +70 -1
  32. anyscale/client/openapi_client/models/task_summary_config.py +29 -3
  33. anyscale/client/openapi_client/models/task_table_config.py +29 -3
  34. anyscale/client/openapi_client/models/unified_event.py +377 -0
  35. anyscale/client/openapi_client/models/{ha_job_event_level.py → unified_origin_filter.py} +21 -9
  36. anyscale/client/openapi_client/models/unifiedevent_list_response.py +147 -0
  37. anyscale/client/openapi_client/models/workspace_event_fields.py +122 -0
  38. anyscale/client/openapi_client/models/workspace_template_version.py +30 -1
  39. anyscale/client/openapi_client/models/workspace_template_version_data_object.py +30 -1
  40. anyscale/cloud/models.py +2 -2
  41. anyscale/commands/cloud_commands.py +133 -2
  42. anyscale/commands/job_commands.py +1 -1
  43. anyscale/commands/service_commands.py +130 -67
  44. anyscale/commands/setup_k8s.py +546 -31
  45. anyscale/controllers/cloud_controller.py +15 -2
  46. anyscale/controllers/kubernetes_verifier.py +80 -66
  47. anyscale/job/_private/job_sdk.py +47 -1
  48. anyscale/job/commands.py +3 -0
  49. anyscale/sdk/anyscale_client/models/apply_production_service_v2_model.py +31 -3
  50. anyscale/sdk/anyscale_client/models/apply_service_model.py +31 -3
  51. anyscale/sdk/anyscale_client/models/baseimagesenum.py +70 -1
  52. anyscale/sdk/anyscale_client/models/rollout_strategy.py +2 -1
  53. anyscale/sdk/anyscale_client/models/supportedbaseimagesenum.py +70 -1
  54. anyscale/service/__init__.py +11 -3
  55. anyscale/service/_private/service_sdk.py +361 -35
  56. anyscale/service/commands.py +15 -3
  57. anyscale/service/models.py +12 -0
  58. anyscale/shared_anyscale_utils/latest_ray_version.py +1 -1
  59. anyscale/version.py +1 -1
  60. {anyscale-0.26.69.dist-info → anyscale-0.26.70.dist-info}/METADATA +1 -1
  61. {anyscale-0.26.69.dist-info → anyscale-0.26.70.dist-info}/RECORD +66 -59
  62. anyscale/client/openapi_client/models/o_auth_connection_response.py +0 -229
  63. {anyscale-0.26.69.dist-info → anyscale-0.26.70.dist-info}/WHEEL +0 -0
  64. {anyscale-0.26.69.dist-info → anyscale-0.26.70.dist-info}/entry_points.txt +0 -0
  65. {anyscale-0.26.69.dist-info → anyscale-0.26.70.dist-info}/licenses/LICENSE +0 -0
  66. {anyscale-0.26.69.dist-info → anyscale-0.26.70.dist-info}/licenses/NOTICE +0 -0
  67. {anyscale-0.26.69.dist-info → anyscale-0.26.70.dist-info}/top_level.txt +0 -0
@@ -40,6 +40,7 @@ class WorkspaceTemplateVersion(object):
40
40
  'id': 'str',
41
41
  'version': 'int',
42
42
  'creator_id': 'str',
43
+ 'creator_email': 'str',
43
44
  'created_at': 'datetime'
44
45
  }
45
46
 
@@ -51,10 +52,11 @@ class WorkspaceTemplateVersion(object):
51
52
  'id': 'id',
52
53
  'version': 'version',
53
54
  'creator_id': 'creator_id',
55
+ 'creator_email': 'creator_email',
54
56
  'created_at': 'created_at'
55
57
  }
56
58
 
57
- def __init__(self, template_id=None, image_uri=None, compute_configs=None, artifacts=None, id=None, version=None, creator_id=None, created_at=None, local_vars_configuration=None): # noqa: E501
59
+ def __init__(self, template_id=None, image_uri=None, compute_configs=None, artifacts=None, id=None, version=None, creator_id=None, creator_email=None, created_at=None, local_vars_configuration=None): # noqa: E501
58
60
  """WorkspaceTemplateVersion - a model defined in OpenAPI""" # noqa: E501
59
61
  if local_vars_configuration is None:
60
62
  local_vars_configuration = Configuration()
@@ -67,6 +69,7 @@ class WorkspaceTemplateVersion(object):
67
69
  self._id = None
68
70
  self._version = None
69
71
  self._creator_id = None
72
+ self._creator_email = None
70
73
  self._created_at = None
71
74
  self.discriminator = None
72
75
 
@@ -80,6 +83,7 @@ class WorkspaceTemplateVersion(object):
80
83
  self.id = id
81
84
  self.version = version
82
85
  self.creator_id = creator_id
86
+ self.creator_email = creator_email
83
87
  self.created_at = created_at
84
88
 
85
89
  @property
@@ -251,6 +255,31 @@ class WorkspaceTemplateVersion(object):
251
255
 
252
256
  self._creator_id = creator_id
253
257
 
258
+ @property
259
+ def creator_email(self):
260
+ """Gets the creator_email of this WorkspaceTemplateVersion. # noqa: E501
261
+
262
+ Email of the creator # noqa: E501
263
+
264
+ :return: The creator_email of this WorkspaceTemplateVersion. # noqa: E501
265
+ :rtype: str
266
+ """
267
+ return self._creator_email
268
+
269
+ @creator_email.setter
270
+ def creator_email(self, creator_email):
271
+ """Sets the creator_email of this WorkspaceTemplateVersion.
272
+
273
+ Email of the creator # noqa: E501
274
+
275
+ :param creator_email: The creator_email of this WorkspaceTemplateVersion. # noqa: E501
276
+ :type: str
277
+ """
278
+ if self.local_vars_configuration.client_side_validation and creator_email is None: # noqa: E501
279
+ raise ValueError("Invalid value for `creator_email`, must not be `None`") # noqa: E501
280
+
281
+ self._creator_email = creator_email
282
+
254
283
  @property
255
284
  def created_at(self):
256
285
  """Gets the created_at of this WorkspaceTemplateVersion. # noqa: E501
@@ -40,6 +40,7 @@ class WorkspaceTemplateVersionDataObject(object):
40
40
  'id': 'str',
41
41
  'version': 'int',
42
42
  'creator_id': 'str',
43
+ 'creator_email': 'str',
43
44
  'created_at': 'datetime'
44
45
  }
45
46
 
@@ -51,10 +52,11 @@ class WorkspaceTemplateVersionDataObject(object):
51
52
  'id': 'id',
52
53
  'version': 'version',
53
54
  'creator_id': 'creator_id',
55
+ 'creator_email': 'creator_email',
54
56
  'created_at': 'created_at'
55
57
  }
56
58
 
57
- def __init__(self, template_id=None, image_uri=None, compute_configs=None, artifacts=None, id=None, version=None, creator_id=None, created_at=None, local_vars_configuration=None): # noqa: E501
59
+ def __init__(self, template_id=None, image_uri=None, compute_configs=None, artifacts=None, id=None, version=None, creator_id=None, creator_email=None, created_at=None, local_vars_configuration=None): # noqa: E501
58
60
  """WorkspaceTemplateVersionDataObject - a model defined in OpenAPI""" # noqa: E501
59
61
  if local_vars_configuration is None:
60
62
  local_vars_configuration = Configuration()
@@ -67,6 +69,7 @@ class WorkspaceTemplateVersionDataObject(object):
67
69
  self._id = None
68
70
  self._version = None
69
71
  self._creator_id = None
72
+ self._creator_email = None
70
73
  self._created_at = None
71
74
  self.discriminator = None
72
75
 
@@ -80,6 +83,7 @@ class WorkspaceTemplateVersionDataObject(object):
80
83
  self.id = id
81
84
  self.version = version
82
85
  self.creator_id = creator_id
86
+ self.creator_email = creator_email
83
87
  self.created_at = created_at
84
88
 
85
89
  @property
@@ -251,6 +255,31 @@ class WorkspaceTemplateVersionDataObject(object):
251
255
 
252
256
  self._creator_id = creator_id
253
257
 
258
+ @property
259
+ def creator_email(self):
260
+ """Gets the creator_email of this WorkspaceTemplateVersionDataObject. # noqa: E501
261
+
262
+ Email of the creator # noqa: E501
263
+
264
+ :return: The creator_email of this WorkspaceTemplateVersionDataObject. # noqa: E501
265
+ :rtype: str
266
+ """
267
+ return self._creator_email
268
+
269
+ @creator_email.setter
270
+ def creator_email(self, creator_email):
271
+ """Sets the creator_email of this WorkspaceTemplateVersionDataObject.
272
+
273
+ Email of the creator # noqa: E501
274
+
275
+ :param creator_email: The creator_email of this WorkspaceTemplateVersionDataObject. # noqa: E501
276
+ :type: str
277
+ """
278
+ if self.local_vars_configuration.client_side_validation and creator_email is None: # noqa: E501
279
+ raise ValueError("Invalid value for `creator_email`, must not be `None`") # noqa: E501
280
+
281
+ self._creator_email = creator_email
282
+
254
283
  @property
255
284
  def created_at(self):
256
285
  """Gets the created_at of this WorkspaceTemplateVersionDataObject. # noqa: E501
anyscale/cloud/models.py CHANGED
@@ -497,9 +497,9 @@ compute_stack: VM
497
497
  region: us-west-2
498
498
  networking_mode: PUBLIC
499
499
  object_storage:
500
- bucket_name: s3://my-bucket
500
+ bucket_name: s3://my-bucket
501
501
  file_storage:
502
- file_storage_id: fs-12345678901234567
502
+ file_storage_id: fs-12345678901234567
503
503
  aws_config:
504
504
  vpc_id: vpc-12345678901234567
505
505
  subnet_ids:
@@ -23,7 +23,10 @@ from anyscale.client.openapi_client.models import (
23
23
  from anyscale.client.openapi_client.models.compute_stack import ComputeStack
24
24
  from anyscale.cloud.models import CreateCloudCollaborator, CreateCloudCollaborators
25
25
  from anyscale.commands import command_examples
26
- from anyscale.commands.setup_k8s import setup_kubernetes_cloud
26
+ from anyscale.commands.setup_k8s import (
27
+ setup_kubernetes_cloud,
28
+ setup_kubernetes_cloud_resource,
29
+ )
27
30
  from anyscale.commands.util import AnyscaleCommand, OptionPromptNull
28
31
  from anyscale.controllers.cloud_controller import CloudController
29
32
  from anyscale.util import (
@@ -381,6 +384,134 @@ def cloud_resource_create(
381
384
  print(e)
382
385
 
383
386
 
387
+ @cloud_resource_group.command(
388
+ name="setup",
389
+ help="Set up cloud resources for an existing cloud on a Kubernetes cluster.",
390
+ cls=AnyscaleCommand,
391
+ is_alpha=True,
392
+ )
393
+ @click.option(
394
+ "--provider",
395
+ help="The cloud provider type.",
396
+ required=True,
397
+ type=click.Choice(["aws", "gcp"], case_sensitive=False),
398
+ )
399
+ @click.option(
400
+ "--region", help="Region to set up the resources in.", required=True,
401
+ )
402
+ @click.option(
403
+ "--stack",
404
+ help="The compute stack to use (only k8s is supported for this command).",
405
+ required=False,
406
+ type=click.Choice(["k8s"], case_sensitive=False),
407
+ default="k8s",
408
+ show_default=True,
409
+ )
410
+ @click.option(
411
+ "--cloud",
412
+ help="The name of the existing cloud to add resources to. Either this or --cloud-id is required.",
413
+ type=str,
414
+ required=False,
415
+ )
416
+ @click.option(
417
+ "--cloud-id",
418
+ help="The ID of the existing cloud to add resources to. Either this or --cloud is required.",
419
+ type=str,
420
+ required=False,
421
+ )
422
+ @click.option(
423
+ "--cluster-name", help="Kubernetes cluster name.", required=True, type=str,
424
+ )
425
+ @click.option(
426
+ "--namespace",
427
+ help="Kubernetes namespace for Anyscale operator.",
428
+ required=False,
429
+ type=str,
430
+ default="anyscale-operator",
431
+ )
432
+ @click.option(
433
+ "--project-id",
434
+ help="Globally Unique project ID for GCP clouds (e.g., my-project-abc123)",
435
+ required=False,
436
+ type=str,
437
+ )
438
+ @click.option(
439
+ "--functional-verify",
440
+ help="Verify the cloud is functional. This will check that the cloud can launch workspace/service.",
441
+ required=False,
442
+ is_flag=False,
443
+ flag_value="workspace",
444
+ )
445
+ @click.option(
446
+ "--yes", "-y", is_flag=True, default=False, help="Skip asking for confirmation."
447
+ )
448
+ @click.option(
449
+ "--values-file",
450
+ help="Path to save the generated Helm values file (default: auto-generated with timestamp).",
451
+ required=False,
452
+ type=str,
453
+ )
454
+ @click.option(
455
+ "--debug", is_flag=True, default=False, help="Enable debug logging.",
456
+ )
457
+ @click.option(
458
+ "--operator-chart",
459
+ help="Path to operator chart (skips helm repo add/update).",
460
+ required=False,
461
+ type=str,
462
+ hidden=True,
463
+ )
464
+ @click.option(
465
+ "--resource-name",
466
+ help="Name for the cloud resource (optional, will be auto-generated if not provided)",
467
+ required=False,
468
+ type=str,
469
+ default=None,
470
+ )
471
+ def cloud_resource_setup( # noqa: PLR0913
472
+ provider: str,
473
+ region: str,
474
+ stack: str,
475
+ cloud: Optional[str],
476
+ cloud_id: Optional[str],
477
+ cluster_name: str,
478
+ namespace: str,
479
+ project_id: Optional[str],
480
+ functional_verify: Optional[str],
481
+ yes: bool,
482
+ values_file: Optional[str],
483
+ debug: bool,
484
+ operator_chart: Optional[str],
485
+ resource_name: Optional[str],
486
+ ) -> None:
487
+ """
488
+ Set up cloud resources for an existing Anyscale cloud on a Kubernetes cluster.
489
+
490
+ This command sets up infrastructure (S3/GCS buckets, IAM roles, etc.) and installs
491
+ the Anyscale operator on your Kubernetes cluster, then creates a cloud resource in
492
+ an existing cloud instead of registering a new cloud.
493
+ """
494
+ # Validate stack
495
+ if stack != "k8s":
496
+ raise click.ClickException("Only --stack=k8s is supported for this command.")
497
+
498
+ setup_kubernetes_cloud_resource(
499
+ provider=provider,
500
+ region=region,
501
+ cloud_name=cloud,
502
+ cloud_id=cloud_id,
503
+ cluster_name=cluster_name,
504
+ namespace=namespace,
505
+ project_id=project_id,
506
+ functional_verify=bool(functional_verify),
507
+ yes=yes,
508
+ values_file=values_file,
509
+ debug=debug,
510
+ operator_chart=operator_chart,
511
+ resource_name=resource_name,
512
+ )
513
+
514
+
384
515
  @cloud_resource_group.command(
385
516
  name="delete",
386
517
  help="Remove a cloud resource from an existing cloud.",
@@ -451,7 +582,7 @@ def cloud_resource_delete(cloud: str, resource: str, yes: bool,) -> None:
451
582
  @click.option(
452
583
  "--resources-file",
453
584
  "-f",
454
- help="EXPERIMENTAL: Path to a YAML file defining a list of cloud resources. Schema: https://docs.anyscale.com/reference/cloud/#cloudresource.",
585
+ help="EXPERIMENTAL: Path to a YAML file defining a single cloud resource or a list of cloud resources. Schema: https://docs.anyscale.com/reference/cloud/#cloudresource.",
455
586
  required=False,
456
587
  )
457
588
  @click.option(
@@ -347,7 +347,7 @@ and override the entrypoint with `python main.py`.
347
347
  log.info("Use `--wait` to wait for the job to run and stream logs.")
348
348
 
349
349
  if wait:
350
- anyscale.job.wait(id=job_id)
350
+ anyscale.job.wait(id=job_id, follow=True)
351
351
 
352
352
 
353
353
  # TODO(mowen): Add cloud support for this when we refactor to new SDK method
@@ -79,8 +79,9 @@ def _read_name_from_config_file(path: str):
79
79
  "-f",
80
80
  "--config-file",
81
81
  required=False,
82
- default=None,
82
+ default=[],
83
83
  type=str,
84
+ multiple=True,
84
85
  help="Path to a YAML config file to deploy. When deploying from a file, import path and arguments cannot be provided. Command-line flags will overwrite values read from the file.",
85
86
  )
86
87
  @click.option(
@@ -202,8 +203,15 @@ def _read_name_from_config_file(path: str):
202
203
  type=str,
203
204
  help="Named project to use for the service. If not provided, the default project for the cloud will be used (or, if running in a workspace, the project of the workspace).",
204
205
  )
206
+ @click.option(
207
+ "--versions",
208
+ required=False,
209
+ default=None,
210
+ type=str,
211
+ help="Defines the traffic and capacity percents per version. Capacity defaults to traffic.",
212
+ )
205
213
  def deploy( # noqa: PLR0912, PLR0913 C901
206
- config_file: Optional[str],
214
+ config_file: List[str],
207
215
  import_path: Optional[str],
208
216
  arguments: Tuple[str],
209
217
  name: Optional[str],
@@ -222,6 +230,7 @@ def deploy( # noqa: PLR0912, PLR0913 C901
222
230
  py_module: Tuple[str],
223
231
  cloud: Optional[str],
224
232
  project: Optional[str],
233
+ versions: Optional[str],
225
234
  ):
226
235
  """Deploy or update a service.
227
236
 
@@ -238,102 +247,156 @@ def deploy( # noqa: PLR0912, PLR0913 C901
238
247
  Command-line flags override values in the config file.
239
248
  """
240
249
 
241
- if config_file is not None:
242
- if import_path is not None or len(arguments) > 0:
250
+ if versions is None:
251
+ if len(config_file) == 1:
252
+ if import_path is not None or len(arguments) > 0:
253
+ raise click.ClickException(
254
+ "When a config file is provided, import path and application arguments can't be."
255
+ )
256
+
257
+ if not pathlib.Path(config_file[0]).is_file():
258
+ raise click.ClickException(f"Config file '{config_file[0]}' not found.")
259
+
260
+ config = ServiceConfig.from_yaml(config_file[0])
261
+ elif len(config_file) > 1:
243
262
  raise click.ClickException(
244
- "When a config file is provided, import path and application arguments can't be."
263
+ "Multiple config files can be provided only when deploying multiple versions with --versions."
245
264
  )
265
+ else:
266
+ # when config_file is not provided.
267
+ if import_path is None:
268
+ raise click.ClickException(
269
+ "Either config file or import path must be provided."
270
+ )
271
+
272
+ if (
273
+ import_path.endswith((".yaml", ".yml"))
274
+ or pathlib.Path(import_path).is_file()
275
+ ):
276
+ log.warning(
277
+ f"The provided import path '{import_path}' looks like a config file. Did you mean to use '-f config.yaml'?"
278
+ )
246
279
 
247
- if not pathlib.Path(config_file).is_file():
248
- raise click.ClickException(f"Config file '{config_file}' not found.")
280
+ app: Dict[str, Any] = {"import_path": import_path}
281
+ arguments_dict = convert_kv_strings_to_dict(arguments)
282
+ if arguments_dict:
283
+ app["args"] = arguments_dict
249
284
 
250
- config = ServiceConfig.from_yaml(config_file)
251
- else:
252
- if import_path is None:
285
+ config = ServiceConfig(applications=[app])
286
+
287
+ if containerfile and image_uri:
288
+ raise click.ClickException(
289
+ "Only one of '--containerfile' and '--image-uri' can be provided."
290
+ )
291
+
292
+ if ray_version and (not image_uri and not containerfile):
253
293
  raise click.ClickException(
254
- "Either config file or import path must be provided."
294
+ "Ray version can only be used with an image or containerfile.",
255
295
  )
256
296
 
257
- if (
258
- import_path.endswith((".yaml", ".yml"))
259
- or pathlib.Path(import_path).is_file()
297
+ if registry_login_secret and (
298
+ not image_uri or ImageURI.from_str(image_uri).is_cluster_env_image()
260
299
  ):
261
- log.warning(
262
- f"The provided import path '{import_path}' looks like a config file. Did you mean to use '-f config.yaml'?"
300
+ raise click.ClickException(
301
+ "Registry login secret can only be used with an image that is not hosted on Anyscale."
263
302
  )
264
303
 
265
- app: Dict[str, Any] = {"import_path": import_path}
266
- arguments_dict = convert_kv_strings_to_dict(arguments)
267
- if arguments_dict:
268
- app["args"] = arguments_dict
304
+ if name is not None:
305
+ config = config.options(name=name)
269
306
 
270
- config = ServiceConfig(applications=[app])
307
+ if image_uri is not None:
308
+ config = config.options(image_uri=image_uri)
271
309
 
272
- if containerfile and image_uri:
273
- raise click.ClickException(
274
- "Only one of '--containerfile' and '--image-uri' can be provided."
275
- )
310
+ if registry_login_secret is not None:
311
+ config = config.options(registry_login_secret=registry_login_secret)
276
312
 
277
- if ray_version and (not image_uri and not containerfile):
278
- raise click.ClickException(
279
- "Ray version can only be used with an image or containerfile.",
280
- )
313
+ if ray_version is not None:
314
+ config = config.options(ray_version=ray_version)
281
315
 
282
- if registry_login_secret and (
283
- not image_uri or ImageURI.from_str(image_uri).is_cluster_env_image()
284
- ):
285
- raise click.ClickException(
286
- "Registry login secret can only be used with an image that is not hosted on Anyscale."
287
- )
316
+ if containerfile is not None:
317
+ config = config.options(containerfile=containerfile)
288
318
 
289
- if name is not None:
290
- config = config.options(name=name)
319
+ if compute_config is not None:
320
+ config = config.options(compute_config=compute_config)
291
321
 
292
- if image_uri is not None:
293
- config = config.options(image_uri=image_uri)
322
+ if working_dir is not None:
323
+ config = config.options(working_dir=working_dir)
294
324
 
295
- if registry_login_secret is not None:
296
- config = config.options(registry_login_secret=registry_login_secret)
325
+ if exclude:
326
+ config = config.options(excludes=[e for e in exclude])
297
327
 
298
- if ray_version is not None:
299
- config = config.options(ray_version=ray_version)
328
+ if requirements is not None:
329
+ config = config.options(requirements=requirements)
300
330
 
301
- if containerfile is not None:
302
- config = config.options(containerfile=containerfile)
331
+ if env:
332
+ config = override_env_vars(config, convert_kv_strings_to_dict(env))
303
333
 
304
- if compute_config is not None:
305
- config = config.options(compute_config=compute_config)
334
+ if py_module:
335
+ for module in py_module:
336
+ if not pathlib.Path(module).is_dir():
337
+ raise click.ClickException(
338
+ f"Python module path '{module}' does not exist or is not a directory."
339
+ )
340
+ config = config.options(py_modules=[*py_module])
306
341
 
307
- if working_dir is not None:
308
- config = config.options(working_dir=working_dir)
342
+ if cloud is not None:
343
+ config = config.options(cloud=cloud)
344
+ if project is not None:
345
+ config = config.options(project=project)
309
346
 
310
- if exclude:
311
- config = config.options(excludes=[e for e in exclude])
347
+ configs = config
348
+ else:
349
+ # When multiple versions are being deployed.
350
+ configs = [ServiceConfig.from_yaml(config) for config in config_file]
351
+ for config in configs:
352
+ if name is not None:
353
+ config = config.options(name=name)
312
354
 
313
- if requirements is not None:
314
- config = config.options(requirements=requirements)
355
+ if cloud is not None:
356
+ config = config.options(cloud=cloud)
315
357
 
316
- if env:
317
- config = override_env_vars(config, convert_kv_strings_to_dict(env))
358
+ if project is not None:
359
+ config = config.options(project=project)
318
360
 
319
- if py_module:
320
- for module in py_module:
321
- if not pathlib.Path(module).is_dir():
322
- raise click.ClickException(
323
- f"Python module path '{module}' does not exist or is not a directory."
324
- )
325
- config = config.options(py_modules=[*py_module])
361
+ if image_uri is not None:
362
+ log.warning("--image-uri is ignored.")
363
+
364
+ if registry_login_secret is not None:
365
+ log.warning("--registry-login-secret is ignored.")
366
+
367
+ if ray_version is not None:
368
+ log.warning("--ray-version is ignored.")
369
+
370
+ if containerfile is not None:
371
+ log.warning("--containerfile is ignored.")
372
+
373
+ if compute_config is not None:
374
+ log.warning("--compute-config is ignored.")
326
375
 
327
- if cloud is not None:
328
- config = config.options(cloud=cloud)
329
- if project is not None:
330
- config = config.options(project=project)
376
+ if working_dir is not None:
377
+ log.warning("--working-dir is ignored.")
378
+
379
+ if exclude:
380
+ log.warning("--exclude is ignored.")
381
+
382
+ if requirements is not None:
383
+ log.warning("--requirements is ignored.")
384
+
385
+ if env:
386
+ log.warning("--env is ignored.")
387
+
388
+ if py_module:
389
+ log.warning("--py-module is ignored.")
331
390
 
332
391
  anyscale.service.deploy(
333
- config,
392
+ configs,
334
393
  in_place=in_place,
335
394
  canary_percent=canary_percent,
336
395
  max_surge_percent=max_surge_percent,
396
+ versions=versions,
397
+ name=name,
398
+ cloud=cloud,
399
+ project=project,
337
400
  )
338
401
 
339
402