diff --git a/sky/backends/backend_utils.py b/sky/backends/backend_utils.py index caa6c9292d5..da1e68991a4 100644 --- a/sky/backends/backend_utils.py +++ b/sky/backends/backend_utils.py @@ -401,6 +401,8 @@ class SSHConfigHelper(object): ssh_conf_path = '~/.ssh/config' ssh_conf_lock_path = os.path.expanduser('~/.sky/ssh_config.lock') + ssh_conf_per_cluster_lock_path = os.path.expanduser( + '~/.sky/ssh_config_{}.lock') ssh_cluster_path = SKY_USER_FILE_PATH + '/ssh/{}' @classmethod @@ -486,12 +488,6 @@ def add_cluster( config_path = os.path.expanduser(cls.ssh_conf_path) - # For backward compatibility: before #2706, we wrote the config of SkyPilot clusters - # directly in ~/.ssh/config. For these clusters, we remove the config in ~/.ssh/config - # and write/overwrite the config in ~/.sky/ssh/ instead. - cls._remove_stale_cluster_config_for_backward_compatibility( - cluster_name, ip, auth_config, docker_user) - if not os.path.exists(config_path): config = ['\n'] with open(config_path, @@ -560,139 +556,20 @@ def add_cluster( f.write(codegen) @classmethod - def _remove_stale_cluster_config_for_backward_compatibility( - cls, - cluster_name: str, - ip: str, - auth_config: Dict[str, str], - docker_user: Optional[str] = None, - ): - """Remove authentication information for cluster from local SSH config. - - If no existing host matching the provided specification is found, then - nothing is removed. - - Args: - ip: Head node's IP address. - auth_config: read_yaml(handle.cluster_yaml)['auth'] - docker_user: If not None, use this user to ssh into the docker - """ - username = auth_config['ssh_user'] - config_path = os.path.expanduser(cls.ssh_conf_path) - cluster_config_path = os.path.expanduser( - cls.ssh_cluster_path.format(cluster_name)) - if not os.path.exists(config_path): - return - - with open(config_path, 'r', encoding='utf-8') as f: - config = f.readlines() - - start_line_idx = None - - # Scan the config for the cluster name. - for i, line in enumerate(config): - next_line = config[i + 1] if i + 1 < len(config) else '' - if docker_user is None: - found = (line.strip() == f'HostName {ip}' and - next_line.strip() == f'User {username}') - else: - found = (line.strip() == 'HostName localhost' and - next_line.strip() == f'User {docker_user}') - if found: - # Find the line starting with ProxyCommand and contains the ip - found = False - for idx in range(i, len(config)): - # Stop if we reach an empty line, which means a new host - if not config[idx].strip(): - break - if config[idx].strip().startswith('ProxyCommand'): - proxy_command_line = config[idx].strip() - if proxy_command_line.endswith(f'@{ip}'): - found = True - break - if found: - start_line_idx = i - 1 - break - - if start_line_idx is not None: - # Scan for end of previous config. - cursor = start_line_idx - while cursor > 0 and len(config[cursor].strip()) > 0: - cursor -= 1 - prev_end_line_idx = cursor - - # Scan for end of the cluster config. - end_line_idx = None - cursor = start_line_idx + 1 - start_line_idx -= 1 # remove auto-generated comment - while cursor < len(config): - if config[cursor].strip().startswith( - '# ') or config[cursor].strip().startswith('Host '): - end_line_idx = cursor - break - cursor += 1 - - # Remove sky-generated config and update the file. - config[prev_end_line_idx:end_line_idx] = [ - '\n' - ] if end_line_idx is not None else [] - with open(config_path, 'w', encoding='utf-8') as f: - f.write(''.join(config).strip()) - f.write('\n' * 2) - - # Delete include statement if it exists in the config. - sky_autogen_comment = ('# Added by sky (use `sky stop/down ' - f'{cluster_name}` to remove)') - with open(config_path, 'r', encoding='utf-8') as f: - config = f.readlines() - - for i, line in enumerate(config): - config_str = line.strip() - if f'Include {cluster_config_path}' in config_str: - with open(config_path, 'w', encoding='utf-8') as f: - if i < len(config) - 1 and config[i + 1] == '\n': - del config[i + 1] - # Delete Include string - del config[i] - # Delete Sky Autogen Comment - if i > 0 and sky_autogen_comment in config[i - 1].strip(): - del config[i - 1] - f.write(''.join(config)) - break - if 'Host' in config_str: - break - - @classmethod - # TODO: We can remove this after 0.6.0 and have a lock only per cluster. - @timeline.FileLockEvent(ssh_conf_lock_path) - def remove_cluster( - cls, - cluster_name: str, - ip: str, - auth_config: Dict[str, str], - docker_user: Optional[str] = None, - ): + def remove_cluster(cls, cluster_name: str): """Remove authentication information for cluster from ~/.sky/ssh/. - For backward compatibility also remove the config from ~/.ssh/config if it exists. - If no existing host matching the provided specification is found, then nothing is removed. Args: - ip: Head node's IP address. - auth_config: read_yaml(handle.cluster_yaml)['auth'] - docker_user: If not None, use this user to ssh into the docker + cluster_name: Cluster name. """ - cluster_config_path = os.path.expanduser( - cls.ssh_cluster_path.format(cluster_name)) - common_utils.remove_file_if_exists(cluster_config_path) - - # Ensures backward compatibility: before #2706, we wrote the config of SkyPilot clusters - # directly in ~/.ssh/config. For these clusters, we should clean up the config. - # TODO: Remove this after 0.6.0 - cls._remove_stale_cluster_config_for_backward_compatibility( - cluster_name, ip, auth_config, docker_user) + with timeline.FileLockEvent( + cls.ssh_conf_per_cluster_lock_path.format(cluster_name)): + cluster_config_path = os.path.expanduser( + cls.ssh_cluster_path.format(cluster_name)) + common_utils.remove_file_if_exists(cluster_config_path) def _replace_yaml_dicts( @@ -867,7 +744,7 @@ def write_cluster_config( labels = skypilot_config.get_nested((str(cloud).lower(), 'labels'), {}) # Deprecated: instance_tags have been replaced by labels. For backward # compatibility, we support them and the schema allows them only if - # `labels` are not specified. This should be removed after 0.7.0. + # `labels` are not specified. This should be removed after 0.8.0. labels = skypilot_config.get_nested((str(cloud).lower(), 'instance_tags'), labels) # labels is a dict, which is guaranteed by the type check in diff --git a/sky/backends/cloud_vm_ray_backend.py b/sky/backends/cloud_vm_ray_backend.py index f0fb4d97ba1..ec86a622c60 100644 --- a/sky/backends/cloud_vm_ray_backend.py +++ b/sky/backends/cloud_vm_ray_backend.py @@ -2118,13 +2118,8 @@ def __init__( stable_internal_external_ips: Optional[List[Tuple[str, str]]] = None, stable_ssh_ports: Optional[List[int]] = None, - cluster_info: Optional[provision_common.ClusterInfo] = None, - # The following 2 fields are deprecated. SkyPilot new provisioner - # API handles the TPU node creation/deletion. - # Backward compatibility for TPU nodes created before #2943. - # TODO (zhwu): Remove this after 0.6.0. - tpu_create_script: Optional[str] = None, - tpu_delete_script: Optional[str] = None) -> None: + cluster_info: Optional[provision_common.ClusterInfo] = None + ) -> None: self._version = self._VERSION self.cluster_name = cluster_name self.cluster_name_on_cloud = cluster_name_on_cloud @@ -2139,12 +2134,6 @@ def __init__( self.launched_nodes = launched_nodes self.launched_resources = launched_resources self.docker_user: Optional[str] = None - # Deprecated. SkyPilot new provisioner API handles the TPU node - # creation/deletion. - # Backward compatibility for TPU nodes created before #2943. - # TODO (zhwu): Remove this after 0.6.0. - self.tpu_create_script = tpu_create_script - self.tpu_delete_script = tpu_delete_script def __repr__(self): return (f'ResourceHandle(' @@ -2160,10 +2149,7 @@ def __repr__(self): f'\n\tlaunched_resources={self.launched_nodes}x ' f'{self.launched_resources}, ' f'\n\tdocker_user={self.docker_user},' - f'\n\tssh_user={self.ssh_user},' - # TODO (zhwu): Remove this after 0.6.0. - f'\n\ttpu_create_script={self.tpu_create_script}, ' - f'\n\ttpu_delete_script={self.tpu_delete_script})') + f'\n\tssh_user={self.ssh_user}') def get_cluster_name(self): return self.cluster_name @@ -2176,26 +2162,6 @@ def _use_internal_ips(self): return common_utils.read_yaml(self.cluster_yaml).get( 'provider', {}).get('use_internal_ips', False) - def _update_cluster_region(self): - """Update the region in handle.launched_resources. - - This is for backward compatibility to handle the clusters launched - long before. We should remove this after 0.6.0. - """ - if self.launched_resources.region is not None: - return - - config = common_utils.read_yaml(self.cluster_yaml) - provider = config['provider'] - cloud = self.launched_resources.cloud - if cloud.is_same_cloud(clouds.Azure()): - region = provider['location'] - elif cloud.is_same_cloud(clouds.GCP()) or cloud.is_same_cloud( - clouds.AWS()): - region = provider['region'] - - self.launched_resources = self.launched_resources.copy(region=region) - def update_ssh_ports(self, max_attempts: int = 1) -> None: """Fetches and sets the SSH ports for the cluster nodes. @@ -2567,8 +2533,6 @@ def __setstate__(self, state): if version < 4: self.update_ssh_ports() - self._update_cluster_region() - if version < 8: try: self._update_cluster_info() @@ -2649,8 +2613,6 @@ def check_resources_fit_cluster( if record is not None: usage_lib.messages.usage.update_cluster_status(record['status']) - # Backward compatibility: the old launched_resources without region info - # was handled by ResourceHandle._update_cluster_region. assert launched_resources.region is not None, handle mismatch_str = (f'To fix: specify a new cluster name, or down the ' @@ -4081,55 +4043,9 @@ def post_teardown_cleanup(self, * Removing ssh configs for the cluster; * Updating the local state of the cluster; * Removing the terminated cluster's scripts and ray yaml files. - - Raises: - RuntimeError: If it fails to delete the TPU. """ - log_path = os.path.join(os.path.expanduser(self.log_dir), - 'teardown.log') - log_abs_path = os.path.abspath(log_path) cluster_name_on_cloud = handle.cluster_name_on_cloud - # Backward compatibility for TPU nodes created before #2943. Any TPU - # node launched before that PR have the delete script generated (and do - # not have the tpu_node config set in its cluster yaml), so we have to - # call the deletion script to clean up the TPU node. - # For TPU nodes launched after the PR, deletion is done in SkyPilot's - # new GCP provisioner API. - # TODO (zhwu): Remove this after 0.6.0. - if (handle.tpu_delete_script is not None and - os.path.exists(handle.tpu_delete_script)): - # Only call the deletion script if the cluster config does not - # contain TPU node config. Otherwise, the deletion should - # already be handled by the new provisioner. - config = common_utils.read_yaml(handle.cluster_yaml) - tpu_node_config = config['provider'].get('tpu_node') - if tpu_node_config is None: - with rich_utils.safe_status( - ux_utils.spinner_message('Terminating TPU')): - tpu_rc, tpu_stdout, tpu_stderr = log_lib.run_with_log( - ['bash', handle.tpu_delete_script], - log_abs_path, - stream_logs=False, - require_outputs=True) - if tpu_rc != 0: - if _TPU_NOT_FOUND_ERROR in tpu_stderr: - logger.info('TPU not found. ' - 'It should have been deleted already.') - elif purge: - logger.warning( - _TEARDOWN_PURGE_WARNING.format( - reason='stopping/terminating TPU', - details=tpu_stderr)) - else: - raise RuntimeError( - _TEARDOWN_FAILURE_MESSAGE.format( - extra_reason='It is caused by TPU failure.', - cluster_name=common_utils.cluster_name_in_hint( - handle.cluster_name, cluster_name_on_cloud), - stdout=tpu_stdout, - stderr=tpu_stderr)) - if (terminate and handle.launched_resources.is_image_managed is True): # Delete the image when terminating a "cloned" cluster, i.e., # whose image is created by SkyPilot (--clone-disk-from) @@ -4174,11 +4090,7 @@ def post_teardown_cleanup(self, # The cluster file must exist because the cluster_yaml will only # be removed after the cluster entry in the database is removed. config = common_utils.read_yaml(handle.cluster_yaml) - auth_config = config['auth'] - backend_utils.SSHConfigHelper.remove_cluster(handle.cluster_name, - handle.head_ip, - auth_config, - handle.docker_user) + backend_utils.SSHConfigHelper.remove_cluster(handle.cluster_name) global_user_state.remove_cluster(handle.cluster_name, terminate=terminate) @@ -4187,13 +4099,6 @@ def post_teardown_cleanup(self, # This function could be directly called from status refresh, # where we need to cleanup the cluster profile. metadata_utils.remove_cluster_metadata(handle.cluster_name) - # Clean up TPU creation/deletion scripts - # Backward compatibility for TPU nodes created before #2943. - # TODO (zhwu): Remove this after 0.6.0. - if handle.tpu_delete_script is not None: - assert handle.tpu_create_script is not None - common_utils.remove_file_if_exists(handle.tpu_create_script) - common_utils.remove_file_if_exists(handle.tpu_delete_script) # Clean up generated config # No try-except is needed since Ray will fail to teardown the diff --git a/sky/provision/gcp/instance.py b/sky/provision/gcp/instance.py index 21d04075f59..9872ad73dc7 100644 --- a/sky/provision/gcp/instance.py +++ b/sky/provision/gcp/instance.py @@ -632,13 +632,6 @@ def cleanup_ports( del ports # Unused. assert provider_config is not None, cluster_name_on_cloud project_id = provider_config['project_id'] - if 'ports' in provider_config: - # Backward compatibility for old provider config. - # TODO(tian): remove this after 2 minor releases, 0.6.0. - for port in provider_config['ports']: - firewall_rule_name = f'user-ports-{cluster_name_on_cloud}-{port}' - instance_utils.GCPComputeInstance.delete_firewall_rule( - project_id, firewall_rule_name) if 'firewall_rule' in provider_config: firewall_rule_name = provider_config['firewall_rule'] instance_utils.GCPComputeInstance.delete_firewall_rule( diff --git a/sky/serve/core.py b/sky/serve/core.py index 691a3edea0b..ea8f380a2e7 100644 --- a/sky/serve/core.py +++ b/sky/serve/core.py @@ -572,8 +572,6 @@ def status( 'controller_port': (Optional[int]) controller port, 'load_balancer_port': (Optional[int]) load balancer port, 'policy': (Optional[str]) load balancer policy description, - 'requested_resources': (sky.Resources) requested resources - for replica (deprecated), 'requested_resources_str': (str) str representation of requested resources, 'replica_info': (List[Dict[str, Any]]) replica information, diff --git a/sky/serve/serve_state.py b/sky/serve/serve_state.py index cbc8ef3d8cc..333e0138fb4 100644 --- a/sky/serve/serve_state.py +++ b/sky/serve/serve_state.py @@ -34,7 +34,7 @@ def _get_db_path() -> str: def create_table(cursor: 'sqlite3.Cursor', conn: 'sqlite3.Connection') -> None: """Creates the service and replica tables if they do not exist.""" - # auto_restart column is deprecated. + # auto_restart and requested_resources column is deprecated. cursor.execute("""\ CREATE TABLE IF NOT EXISTS services ( name TEXT PRIMARY KEY, @@ -323,8 +323,8 @@ def set_service_load_balancer_port(service_name: str, def _get_service_from_row(row) -> Dict[str, Any]: (current_version, name, controller_job_id, controller_port, - load_balancer_port, status, uptime, policy, _, requested_resources, - requested_resources_str, _, active_versions) = row[:13] + load_balancer_port, status, uptime, policy, _, _, requested_resources_str, + _, active_versions) = row[:13] return { 'name': name, 'controller_job_id': controller_job_id, @@ -340,10 +340,6 @@ def _get_service_from_row(row) -> Dict[str, Any]: # The versions that is active for the load balancer. This is a list of # integers in json format. This is mainly for display purpose. 'active_versions': json.loads(active_versions), - # TODO(tian): Backward compatibility. - # Remove after 2 minor release, 0.6.0. - 'requested_resources': pickle.loads(requested_resources) - if requested_resources is not None else None, 'requested_resources_str': requested_resources_str, } diff --git a/sky/serve/serve_utils.py b/sky/serve/serve_utils.py index 3a416dd2932..6e7b6f6eb4a 100644 --- a/sky/serve/serve_utils.py +++ b/sky/serve/serve_utils.py @@ -825,12 +825,7 @@ def format_service_table(service_records: List[Dict[str, Any]], replicas = _get_replicas(record) endpoint = get_endpoint(record) policy = record['policy'] - # TODO(tian): Backward compatibility. - # Remove `requested_resources` field after 2 minor release, 0.6.0. - if record.get('requested_resources_str') is None: - requested_resources_str = str(record['requested_resources']) - else: - requested_resources_str = record['requested_resources_str'] + requested_resources_str = record['requested_resources_str'] service_values = [ service_name, @@ -1004,15 +999,8 @@ def _build(cls, code: List[str]) -> str: @classmethod def update_service(cls, service_name: str, version: int, mode: str) -> str: code = [ - # Backward compatibility for old serve version on the remote - # machine. The `mode` argument was added in #3249, and if the remote - # machine has an old SkyPilot version before that, we need to avoid - # passing the `mode` argument to the job_lib functions. - # TODO(zhwu): Remove this in 0.7.0 release. - f'mode_kwargs = {{"mode": {mode!r}}} ' - 'if getattr(constants, "SERVE_VERSION", 0) >= 1 else {}', f'msg = serve_utils.update_service_encoded({service_name!r}, ' - f'{version}, **mode_kwargs)', + f'{version}, mode={mode!r})', 'print(msg, end="", flush=True)', ] return cls._build(code) diff --git a/sky/serve/service_spec.py b/sky/serve/service_spec.py index 3a97a6f8521..2eff6f40a9d 100644 --- a/sky/serve/service_spec.py +++ b/sky/serve/service_spec.py @@ -29,13 +29,6 @@ def __init__( base_ondemand_fallback_replicas: Optional[int] = None, upscale_delay_seconds: Optional[int] = None, downscale_delay_seconds: Optional[int] = None, - # The following arguments are deprecated. - # TODO(ziming): remove this after 2 minor release, i.e. 0.6.0. - # Deprecated: Always be True - auto_restart: Optional[bool] = None, - # Deprecated: replaced by the target_qps_per_replica. - qps_upper_threshold: Optional[float] = None, - qps_lower_threshold: Optional[float] = None, ) -> None: if max_replicas is not None and max_replicas < min_replicas: with ux_utils.print_exception_no_traceback(): @@ -62,21 +55,6 @@ def __init__( raise ValueError('readiness_path must start with a slash (/). ' f'Got: {readiness_path}') - # TODO(tian): Following field are deprecated. Remove after 2 minor - # release, i.e. 0.6.0. - if qps_upper_threshold is not None or qps_lower_threshold is not None: - with ux_utils.print_exception_no_traceback(): - raise ValueError( - 'Field `qps_upper_threshold` and `qps_lower_threshold`' - 'under `replica_policy` are deprecated. ' - 'Please use target_qps_per_replica instead.') - if auto_restart is not None: - with ux_utils.print_exception_no_traceback(): - raise ValueError( - 'Field `auto_restart` under `replica_policy` is deprecated.' - 'Currently, SkyServe will cleanup failed replicas' - 'and auto restart it to keep the service running.') - self._readiness_path: str = readiness_path self._initial_delay_seconds: int = initial_delay_seconds self._readiness_timeout_seconds: int = readiness_timeout_seconds @@ -160,14 +138,8 @@ def from_yaml_config(config: Dict[str, Any]) -> 'SkyServiceSpec': service_config['min_replicas'] = policy_section['min_replicas'] service_config['max_replicas'] = policy_section.get( 'max_replicas', None) - service_config['qps_upper_threshold'] = policy_section.get( - 'qps_upper_threshold', None) - service_config['qps_lower_threshold'] = policy_section.get( - 'qps_lower_threshold', None) service_config['target_qps_per_replica'] = policy_section.get( 'target_qps_per_replica', None) - service_config['auto_restart'] = policy_section.get( - 'auto_restart', None) service_config['upscale_delay_seconds'] = policy_section.get( 'upscale_delay_seconds', None) service_config['downscale_delay_seconds'] = policy_section.get( diff --git a/sky/skylet/job_lib.py b/sky/skylet/job_lib.py index 5e7008e55d8..17908a1aec5 100644 --- a/sky/skylet/job_lib.py +++ b/sky/skylet/job_lib.py @@ -827,14 +827,6 @@ class JobLibCodeGen: 'import os', 'import getpass', 'from sky.skylet import job_lib, log_lib, constants', - # Backward compatibility for old skylet lib version on the remote - # machine. The `job_owner` argument was removed in #3037, and if the - # remote machine has an old SkyPilot version before that, we need to - # pass the `job_owner` argument to the job_lib functions. - # TODO(zhwu): Remove this in 0.7.0 release. - 'job_owner_kwargs = {} ' - 'if getattr(constants, "SKYLET_LIB_VERSION", 0) >= 1 ' - 'else {"job_owner": getpass.getuser()}', ] @classmethod @@ -861,7 +853,7 @@ def queue_job(cls, job_id: int, cmd: str) -> str: @classmethod def update_status(cls) -> str: - code = ['job_lib.update_status(**job_owner_kwargs)'] + code = ['job_lib.update_status()'] return cls._build(code) @classmethod @@ -879,7 +871,7 @@ def cancel_jobs(cls, """See job_lib.cancel_jobs().""" code = [ (f'cancelled = job_lib.cancel_jobs_encoded_results(' - f' {job_ids!r}, {cancel_all}, **job_owner_kwargs)'), + f' {job_ids!r}, {cancel_all})'), # Print cancelled IDs. Caller should parse by decoding. 'print(cancelled, flush=True)', ] @@ -902,7 +894,7 @@ def tail_logs(cls, 'run_timestamp = job_lib.get_run_timestamp(job_id)', f'log_dir = None if run_timestamp is None else os.path.join({constants.SKY_LOGS_DIRECTORY!r}, run_timestamp)', f'log_lib.tail_logs(job_id=job_id, log_dir=log_dir, ' - f'managed_job_id={managed_job_id!r}, follow={follow}, **job_owner_kwargs)', + f'managed_job_id={managed_job_id!r}, follow={follow})', ] return cls._build(code) diff --git a/sky/skylet/log_lib.py b/sky/skylet/log_lib.py index 9f1483b2b48..eb64440077e 100644 --- a/sky/skylet/log_lib.py +++ b/sky/skylet/log_lib.py @@ -186,20 +186,11 @@ def run_with_log( daemon_script = os.path.join( os.path.dirname(os.path.abspath(job_lib.__file__)), 'subprocess_daemon.py') - if not hasattr(constants, 'SKY_GET_PYTHON_PATH_CMD'): - # Backward compatibility: for cluster started before #3326, this - # constant does not exist. Since we generate the job script - # in backends.cloud_vm_ray_backend with inspect, so the - # the lates `run_with_log` will be used, but the `constants` is - # not updated. We fallback to `python3` in this case. - # TODO(zhwu): remove this after 0.7.0. - python_path = 'python3' - else: - python_path = subprocess.check_output( - constants.SKY_GET_PYTHON_PATH_CMD, - shell=True, - stderr=subprocess.DEVNULL, - encoding='utf-8').strip() + python_path = subprocess.check_output( + constants.SKY_GET_PYTHON_PATH_CMD, + shell=True, + stderr=subprocess.DEVNULL, + encoding='utf-8').strip() daemon_cmd = [ python_path, daemon_script, diff --git a/sky/utils/schemas.py b/sky/utils/schemas.py index 94a6ed690e1..d9f105db8b0 100644 --- a/sky/utils/schemas.py +++ b/sky/utils/schemas.py @@ -357,19 +357,6 @@ def get_service_schema(): 'downscale_delay_seconds': { 'type': 'number', }, - # TODO(MaoZiming): Fields `qps_upper_threshold`, - # `qps_lower_threshold` and `auto_restart` are deprecated. - # Temporarily keep these fields for backward compatibility. - # Remove after 2 minor release, i.e., 0.6.0. - 'auto_restart': { - 'type': 'boolean', - }, - 'qps_upper_threshold': { - 'type': 'number', - }, - 'qps_lower_threshold': { - 'type': 'number', - }, } }, 'replicas': { @@ -595,7 +582,7 @@ def get_cluster_schema(): _LABELS_SCHEMA = { # Deprecated: 'instance_tags' is replaced by 'labels'. Keeping for backward - # compatibility. Will be removed after 0.7.0. + # compatibility. Will be removed after 0.8.0. 'instance_tags': { 'type': 'object', 'required': [], diff --git a/tests/test_jobs_and_serve.py b/tests/test_jobs_and_serve.py index a599fb7ba88..237ffd440da 100644 --- a/tests/test_jobs_and_serve.py +++ b/tests/test_jobs_and_serve.py @@ -307,7 +307,6 @@ def mock_get_services_one_service( 'controller_port': 30001, 'load_balancer_port': 30000, 'policy': None, - 'requested_resources': sky.Resources(), 'requested_resources_str': '', 'replica_info': [], }