anyscale 0.26.43__py3-none-any.whl → 0.26.44__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 (37) hide show
  1. anyscale/_private/anyscale_client/common.py +1 -1
  2. anyscale/_private/docgen/__main__.py +2 -0
  3. anyscale/_private/docgen/models.md +2 -2
  4. anyscale/_private/workload/workload_sdk.py +6 -0
  5. anyscale/client/README.md +6 -0
  6. anyscale/client/openapi_client/__init__.py +5 -0
  7. anyscale/client/openapi_client/api/default_api.py +132 -0
  8. anyscale/client/openapi_client/models/__init__.py +5 -0
  9. anyscale/client/openapi_client/models/baseimagesenum.py +68 -1
  10. anyscale/client/openapi_client/models/describe_machine_pool_machines_filters.py +31 -3
  11. anyscale/client/openapi_client/models/describe_machine_pool_workloads_filters.py +150 -0
  12. anyscale/client/openapi_client/models/describe_machine_pool_workloads_request.py +151 -0
  13. anyscale/client/openapi_client/models/file_storage.py +33 -5
  14. anyscale/client/openapi_client/models/supportedbaseimagesenum.py +68 -1
  15. anyscale/client/openapi_client/models/workload_machine_info.py +210 -0
  16. anyscale/client/openapi_client/models/workload_state_info.py +295 -0
  17. anyscale/client/openapi_client/models/workloadstateinfo_list_response.py +147 -0
  18. anyscale/commands/cloud_commands.py +1 -0
  19. anyscale/commands/compute_config_commands.py +10 -3
  20. anyscale/compute_config/__init__.py +16 -0
  21. anyscale/compute_config/_private/compute_config_sdk.py +172 -60
  22. anyscale/compute_config/commands.py +66 -1
  23. anyscale/compute_config/models.py +160 -3
  24. anyscale/conf.py +1 -1
  25. anyscale/controllers/cloud_controller.py +141 -3
  26. anyscale/job/_private/job_sdk.py +22 -0
  27. anyscale/sdk/anyscale_client/models/baseimagesenum.py +68 -1
  28. anyscale/sdk/anyscale_client/models/supportedbaseimagesenum.py +68 -1
  29. anyscale/shared_anyscale_utils/latest_ray_version.py +1 -1
  30. anyscale/version.py +1 -1
  31. {anyscale-0.26.43.dist-info → anyscale-0.26.44.dist-info}/METADATA +4 -3
  32. {anyscale-0.26.43.dist-info → anyscale-0.26.44.dist-info}/RECORD +37 -32
  33. {anyscale-0.26.43.dist-info → anyscale-0.26.44.dist-info}/LICENSE +0 -0
  34. {anyscale-0.26.43.dist-info → anyscale-0.26.44.dist-info}/NOTICE +0 -0
  35. {anyscale-0.26.43.dist-info → anyscale-0.26.44.dist-info}/WHEEL +0 -0
  36. {anyscale-0.26.43.dist-info → anyscale-0.26.44.dist-info}/entry_points.txt +0 -0
  37. {anyscale-0.26.43.dist-info → anyscale-0.26.44.dist-info}/top_level.txt +0 -0
@@ -2222,6 +2222,7 @@ class CloudController(BaseController):
2222
2222
  nfs_mount_targets: Optional[List[str]] = None,
2223
2223
  nfs_mount_path: Optional[str] = None,
2224
2224
  kubernetes_zones: Optional[List[str]] = None,
2225
+ anyscale_operator_iam_identity: Optional[str] = None,
2225
2226
  ) -> None:
2226
2227
  cloud_provider = (
2227
2228
  CloudProviders.AZURE if provider == "azure" else CloudProviders.GENERIC
@@ -2315,8 +2316,28 @@ class CloudController(BaseController):
2315
2316
 
2316
2317
  # TODO (shomilj): Fetch & optionally run the Helm installation here.
2317
2318
  cloud_resource_id = cloud_resource.result.cloud_resource.id
2319
+ # For Azure and generic providers, add CLI token to helm command
2320
+ if provider in ["azure", "generic"]:
2321
+ helm_command = self._generate_helm_upgrade_command(
2322
+ provider=provider,
2323
+ cloud_deployment_id=cloud_resource_id,
2324
+ region=region if provider != "generic" else None,
2325
+ kubernetes_zones=kubernetes_zones,
2326
+ operator_iam_identity=anyscale_operator_iam_identity
2327
+ if provider == "azure"
2328
+ else None,
2329
+ anyscale_cli_token=None, # TODO: use $ANYSCALE_CLI_TOKEN placeholder
2330
+ )
2331
+ else:
2332
+ helm_command = self._generate_helm_upgrade_command(
2333
+ provider=provider,
2334
+ cloud_deployment_id=cloud_resource_id,
2335
+ region=region,
2336
+ kubernetes_zones=kubernetes_zones,
2337
+ )
2338
+
2318
2339
  self.log.info(
2319
- f"Cloud registration complete! When installing this cloud's Kubernetes Manager, use cloud deployment ID '{cloud_resource_id}'."
2340
+ f"Cloud registration complete! To install the Anyscale operator, run:\n\n{helm_command}"
2320
2341
  )
2321
2342
 
2322
2343
  def register_aws_cloud( # noqa: PLR0913, PLR0912, C901
@@ -2582,8 +2603,14 @@ class CloudController(BaseController):
2582
2603
  self.wait_for_cloud_to_be_active(cloud_id, CloudProviders.AWS)
2583
2604
  if compute_stack == ComputeStack.K8S:
2584
2605
  cloud_resource_id = cloud_resource.result.cloud_resource.id
2606
+ helm_command = self._generate_helm_upgrade_command(
2607
+ provider="aws",
2608
+ cloud_deployment_id=cloud_resource_id,
2609
+ region=region,
2610
+ kubernetes_zones=kubernetes_zones,
2611
+ )
2585
2612
  self.log.info(
2586
- f"For registering this cloud's Kubernetes Manager, use cloud deployment ID '{cloud_resource_id}'."
2613
+ f"Cloud registration complete! To install the Anyscale operator, run:\n\n{helm_command}"
2587
2614
  )
2588
2615
  self.cloud_event_producer.produce(
2589
2616
  CloudAnalyticsEventName.INFRA_SETUP_COMPLETE, succeeded=True
@@ -2968,8 +2995,20 @@ class CloudController(BaseController):
2968
2995
  self.wait_for_cloud_to_be_active(cloud_id, CloudProviders.GCP)
2969
2996
  if compute_stack == ComputeStack.K8S:
2970
2997
  cloud_resource_id = cloud_resource.result.cloud_resource.id
2998
+ helm_command = self._generate_helm_upgrade_command(
2999
+ provider="gcp",
3000
+ cloud_deployment_id=cloud_resource_id,
3001
+ region=region,
3002
+ kubernetes_zones=kubernetes_zones,
3003
+ operator_iam_identity=anyscale_service_account_email,
3004
+ )
3005
+ gcloud_command = self._generate_gcp_workload_identity_command(
3006
+ anyscale_service_account_email=anyscale_service_account_email,
3007
+ project_id=project_id,
3008
+ namespace="<namespace>",
3009
+ )
2971
3010
  self.log.info(
2972
- f"For registering this cloud's Kubernetes Manager, use cloud deployment ID '{cloud_resource_id}'."
3011
+ f"Cloud registration complete! To install the Anyscale operator, run:\n\n{helm_command}\n\nThen configure workload identity by running:\n\n{gcloud_command}"
2973
3012
  )
2974
3013
  self.cloud_event_producer.produce(
2975
3014
  CloudAnalyticsEventName.INFRA_SETUP_COMPLETE, succeeded=True
@@ -3684,6 +3723,105 @@ class CloudController(BaseController):
3684
3723
  )
3685
3724
  return rollback_cmd
3686
3725
 
3726
+ def _generate_helm_upgrade_command(
3727
+ self,
3728
+ provider: str,
3729
+ cloud_deployment_id: str,
3730
+ region: Optional[str] = None,
3731
+ kubernetes_zones: Optional[List[str]] = None,
3732
+ operator_iam_identity: Optional[str] = None,
3733
+ anyscale_cli_token: Optional[str] = None,
3734
+ ) -> str:
3735
+ """
3736
+ Generate the helm upgrade command for installing the Anyscale operator.
3737
+
3738
+ Args:
3739
+ provider: Cloud provider ('aws', 'gcp', 'azure', 'generic')
3740
+ cloud_deployment_id: The cloud deployment ID from registration
3741
+ region: Cloud region (optional for generic provider)
3742
+ kubernetes_zones: Optional list of Kubernetes zones
3743
+ operator_iam_identity: IAM identity for the operator (GCP service account email, Azure client ID)
3744
+ anyscale_cli_token: CLI token (required for Azure and generic providers)
3745
+
3746
+ Returns:
3747
+ Formatted helm upgrade command string
3748
+ """
3749
+ command_parts = [
3750
+ "helm upgrade <release-name> anyscale/anyscale-operator",
3751
+ f" --set-string cloudDeploymentId={cloud_deployment_id}",
3752
+ f" --set-string cloudProvider={provider}",
3753
+ ]
3754
+
3755
+ # Add region for most providers (not for generic)
3756
+ if region and provider != "generic":
3757
+ command_parts.append(f" --set-string region={region}")
3758
+
3759
+ # Add provider-specific parameters
3760
+ if provider == "gcp" and operator_iam_identity:
3761
+ command_parts.append(
3762
+ f" --set-string operatorIamIdentity={operator_iam_identity}"
3763
+ )
3764
+ elif provider == "azure":
3765
+ if operator_iam_identity:
3766
+ command_parts.append(
3767
+ f" --set-string operatorIamIdentity={operator_iam_identity}"
3768
+ )
3769
+ if anyscale_cli_token:
3770
+ command_parts.append(
3771
+ f" --set-string anyscaleCliToken={anyscale_cli_token}"
3772
+ )
3773
+ else:
3774
+ command_parts.append(
3775
+ " --set-string anyscaleCliToken=$ANYSCALE_CLI_TOKEN"
3776
+ )
3777
+ elif provider == "generic":
3778
+ if anyscale_cli_token:
3779
+ command_parts.append(
3780
+ f" --set-string anyscaleCliToken={anyscale_cli_token}"
3781
+ )
3782
+ else:
3783
+ command_parts.append(
3784
+ " --set-string anyscaleCliToken=$ANYSCALE_CLI_TOKEN"
3785
+ )
3786
+
3787
+ # Add common parameters
3788
+ command_parts.extend(
3789
+ [
3790
+ " --set-string workloadServiceAccountName=anyscale-operator",
3791
+ " --namespace <namespace>",
3792
+ " --create-namespace",
3793
+ " -i",
3794
+ ]
3795
+ )
3796
+
3797
+ # Add zones if provided (mainly for K8s deployments)
3798
+ if kubernetes_zones:
3799
+ zones_str = ",".join(kubernetes_zones)
3800
+ command_parts.append(f" --set-string zones={zones_str}")
3801
+
3802
+ return " \\\n".join(command_parts)
3803
+
3804
+ def _generate_gcp_workload_identity_command(
3805
+ self,
3806
+ anyscale_service_account_email: str,
3807
+ project_id: str,
3808
+ namespace: str = "<namespace>",
3809
+ ) -> str:
3810
+ """
3811
+ Generate the gcloud command for setting up workload identity for GCP.
3812
+
3813
+ Args:
3814
+ anyscale_service_account_email: The GCP service account email
3815
+ project_id: The GCP project ID
3816
+ namespace: The Kubernetes namespace (defaults to <namespace> placeholder)
3817
+
3818
+ Returns:
3819
+ Formatted gcloud iam service-accounts add-iam-policy-binding command
3820
+ """
3821
+ return f"""gcloud iam service-accounts add-iam-policy-binding {anyscale_service_account_email} \\
3822
+ --role roles/iam.workloadIdentityUser \\
3823
+ --member "serviceAccount:{project_id}.svc.id.goog[{namespace}/anyscale-operator]" """
3824
+
3687
3825
  def _edit_gcp_cloud( # noqa: PLR0912
3688
3826
  self,
3689
3827
  *,
@@ -87,6 +87,9 @@ class PrivateJobSDK(WorkloadSDK):
87
87
  autopopulate_in_workspace=autopopulate_in_workspace,
88
88
  additional_py_modules=config.py_modules,
89
89
  py_executable_override=config.py_executable,
90
+ has_multiple_cloud_deployments=self._compute_config_has_multiple_cloud_deployments(
91
+ config.compute_config
92
+ ),
90
93
  )
91
94
  [runtime_env] = self.override_and_load_requirements_files(
92
95
  [runtime_env],
@@ -99,6 +102,25 @@ class PrivateJobSDK(WorkloadSDK):
99
102
 
100
103
  return runtime_env or None
101
104
 
105
+ def _compute_config_has_multiple_cloud_deployments(
106
+ self, compute_config: Union[ComputeConfig, Dict, str, None]
107
+ ) -> bool:
108
+ if not isinstance(compute_config, str):
109
+ # Multi-deployment compute configs are not supported in-line, only by name.
110
+ return False
111
+
112
+ compute_config_id = self._resolve_compute_config_id(
113
+ compute_config=compute_config
114
+ )
115
+ compute_template = self._client.get_compute_config(compute_config_id)
116
+ if compute_template is None or compute_template.config is None:
117
+ raise ValueError(f"The compute config '{compute_config}' does not exist.")
118
+
119
+ return (
120
+ compute_template.config.deployment_configs
121
+ and len(compute_template.config.deployment_configs) > 1
122
+ )
123
+
102
124
  def get_default_name(self) -> str:
103
125
  """Get a default name for the job.
104
126