skypilot-nightly 1.0.0.dev20241204__tar.gz → 1.0.0.dev20241205__tar.gz

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 (304) hide show
  1. {skypilot_nightly-1.0.0.dev20241204/skypilot_nightly.egg-info → skypilot_nightly-1.0.0.dev20241205}/PKG-INFO +1 -1
  2. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/__init__.py +2 -2
  3. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/backends/backend.py +42 -15
  4. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/backends/backend_utils.py +138 -5
  5. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/backends/cloud_vm_ray_backend.py +76 -18
  6. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/backends/local_docker_backend.py +11 -7
  7. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/clouds/service_catalog/common.py +2 -2
  8. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/execution.py +27 -9
  9. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/global_user_state.py +23 -10
  10. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/templates/kubernetes-ray.yml.j2 +3 -1
  11. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/utils/common_utils.py +19 -0
  12. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205/skypilot_nightly.egg-info}/PKG-INFO +1 -1
  13. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/LICENSE +0 -0
  14. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/MANIFEST.in +0 -0
  15. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/README.md +0 -0
  16. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/pyproject.toml +0 -0
  17. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/setup.cfg +0 -0
  18. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/setup.py +0 -0
  19. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/adaptors/__init__.py +0 -0
  20. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/adaptors/aws.py +0 -0
  21. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/adaptors/azure.py +0 -0
  22. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/adaptors/cloudflare.py +0 -0
  23. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/adaptors/common.py +0 -0
  24. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/adaptors/cudo.py +0 -0
  25. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/adaptors/docker.py +0 -0
  26. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/adaptors/gcp.py +0 -0
  27. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/adaptors/ibm.py +0 -0
  28. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/adaptors/kubernetes.py +0 -0
  29. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/adaptors/oci.py +0 -0
  30. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/adaptors/runpod.py +0 -0
  31. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/adaptors/vsphere.py +0 -0
  32. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/admin_policy.py +0 -0
  33. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/authentication.py +0 -0
  34. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/backends/__init__.py +0 -0
  35. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/backends/docker_utils.py +0 -0
  36. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/backends/monkey_patches/monkey_patch_ray_up.py +0 -0
  37. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/backends/wheel_utils.py +0 -0
  38. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/benchmark/__init__.py +0 -0
  39. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/benchmark/benchmark_state.py +0 -0
  40. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/benchmark/benchmark_utils.py +0 -0
  41. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/check.py +0 -0
  42. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/cli.py +0 -0
  43. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/cloud_stores.py +0 -0
  44. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/clouds/__init__.py +0 -0
  45. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/clouds/aws.py +0 -0
  46. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/clouds/azure.py +0 -0
  47. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/clouds/cloud.py +0 -0
  48. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/clouds/cloud_registry.py +0 -0
  49. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/clouds/cudo.py +0 -0
  50. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/clouds/fluidstack.py +0 -0
  51. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/clouds/gcp.py +0 -0
  52. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/clouds/ibm.py +0 -0
  53. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/clouds/kubernetes.py +0 -0
  54. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/clouds/lambda_cloud.py +0 -0
  55. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/clouds/oci.py +0 -0
  56. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/clouds/paperspace.py +0 -0
  57. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/clouds/runpod.py +0 -0
  58. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/clouds/scp.py +0 -0
  59. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/clouds/service_catalog/__init__.py +0 -0
  60. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/clouds/service_catalog/aws_catalog.py +0 -0
  61. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/clouds/service_catalog/azure_catalog.py +0 -0
  62. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/clouds/service_catalog/config.py +0 -0
  63. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/clouds/service_catalog/constants.py +0 -0
  64. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/clouds/service_catalog/cudo_catalog.py +0 -0
  65. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/clouds/service_catalog/data_fetchers/__init__.py +0 -0
  66. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/clouds/service_catalog/data_fetchers/fetch_aws.py +0 -0
  67. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/clouds/service_catalog/data_fetchers/fetch_azure.py +0 -0
  68. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/clouds/service_catalog/data_fetchers/fetch_cudo.py +0 -0
  69. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/clouds/service_catalog/data_fetchers/fetch_fluidstack.py +0 -0
  70. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/clouds/service_catalog/data_fetchers/fetch_gcp.py +0 -0
  71. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/clouds/service_catalog/data_fetchers/fetch_lambda_cloud.py +0 -0
  72. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/clouds/service_catalog/data_fetchers/fetch_vsphere.py +0 -0
  73. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/clouds/service_catalog/fluidstack_catalog.py +0 -0
  74. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/clouds/service_catalog/gcp_catalog.py +0 -0
  75. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/clouds/service_catalog/ibm_catalog.py +0 -0
  76. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/clouds/service_catalog/kubernetes_catalog.py +0 -0
  77. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/clouds/service_catalog/lambda_catalog.py +0 -0
  78. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/clouds/service_catalog/oci_catalog.py +0 -0
  79. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/clouds/service_catalog/paperspace_catalog.py +0 -0
  80. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/clouds/service_catalog/runpod_catalog.py +0 -0
  81. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/clouds/service_catalog/scp_catalog.py +0 -0
  82. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/clouds/service_catalog/vsphere_catalog.py +0 -0
  83. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/clouds/utils/__init__.py +0 -0
  84. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/clouds/utils/aws_utils.py +0 -0
  85. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/clouds/utils/azure_utils.py +0 -0
  86. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/clouds/utils/gcp_utils.py +0 -0
  87. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/clouds/utils/oci_utils.py +0 -0
  88. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/clouds/utils/scp_utils.py +0 -0
  89. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/clouds/vsphere.py +0 -0
  90. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/core.py +0 -0
  91. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/dag.py +0 -0
  92. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/data/__init__.py +0 -0
  93. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/data/data_transfer.py +0 -0
  94. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/data/data_utils.py +0 -0
  95. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/data/mounting_utils.py +0 -0
  96. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/data/storage.py +0 -0
  97. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/data/storage_utils.py +0 -0
  98. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/exceptions.py +0 -0
  99. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/jobs/__init__.py +0 -0
  100. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/jobs/constants.py +0 -0
  101. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/jobs/controller.py +0 -0
  102. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/jobs/core.py +0 -0
  103. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/jobs/dashboard/dashboard.py +0 -0
  104. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/jobs/dashboard/static/favicon.ico +0 -0
  105. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/jobs/dashboard/templates/index.html +0 -0
  106. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/jobs/recovery_strategy.py +0 -0
  107. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/jobs/state.py +0 -0
  108. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/jobs/utils.py +0 -0
  109. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/optimizer.py +0 -0
  110. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/__init__.py +0 -0
  111. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/aws/__init__.py +0 -0
  112. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/aws/config.py +0 -0
  113. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/aws/instance.py +0 -0
  114. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/aws/utils.py +0 -0
  115. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/azure/__init__.py +0 -0
  116. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/azure/azure-config-template.json +0 -0
  117. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/azure/config.py +0 -0
  118. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/azure/instance.py +0 -0
  119. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/common.py +0 -0
  120. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/constants.py +0 -0
  121. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/cudo/__init__.py +0 -0
  122. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/cudo/config.py +0 -0
  123. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/cudo/cudo_machine_type.py +0 -0
  124. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/cudo/cudo_utils.py +0 -0
  125. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/cudo/cudo_wrapper.py +0 -0
  126. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/cudo/instance.py +0 -0
  127. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/docker_utils.py +0 -0
  128. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/fluidstack/__init__.py +0 -0
  129. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/fluidstack/config.py +0 -0
  130. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/fluidstack/fluidstack_utils.py +0 -0
  131. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/fluidstack/instance.py +0 -0
  132. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/gcp/__init__.py +0 -0
  133. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/gcp/config.py +0 -0
  134. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/gcp/constants.py +0 -0
  135. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/gcp/instance.py +0 -0
  136. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/gcp/instance_utils.py +0 -0
  137. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/gcp/mig_utils.py +0 -0
  138. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/instance_setup.py +0 -0
  139. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/kubernetes/__init__.py +0 -0
  140. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/kubernetes/config.py +0 -0
  141. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/kubernetes/instance.py +0 -0
  142. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/kubernetes/manifests/smarter-device-manager-configmap.yaml +0 -0
  143. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/kubernetes/manifests/smarter-device-manager-daemonset.yaml +0 -0
  144. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/kubernetes/network.py +0 -0
  145. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/kubernetes/network_utils.py +0 -0
  146. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/kubernetes/utils.py +0 -0
  147. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/lambda_cloud/__init__.py +0 -0
  148. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/lambda_cloud/config.py +0 -0
  149. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/lambda_cloud/instance.py +0 -0
  150. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/lambda_cloud/lambda_utils.py +0 -0
  151. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/logging.py +0 -0
  152. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/metadata_utils.py +0 -0
  153. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/oci/__init__.py +0 -0
  154. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/oci/config.py +0 -0
  155. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/oci/instance.py +0 -0
  156. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/oci/query_utils.py +0 -0
  157. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/paperspace/__init__.py +0 -0
  158. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/paperspace/config.py +0 -0
  159. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/paperspace/constants.py +0 -0
  160. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/paperspace/instance.py +0 -0
  161. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/paperspace/utils.py +0 -0
  162. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/provisioner.py +0 -0
  163. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/runpod/__init__.py +0 -0
  164. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/runpod/config.py +0 -0
  165. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/runpod/instance.py +0 -0
  166. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/runpod/utils.py +0 -0
  167. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/vsphere/__init__.py +0 -0
  168. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/vsphere/common/__init__.py +0 -0
  169. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/vsphere/common/cls_api_client.py +0 -0
  170. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/vsphere/common/cls_api_helper.py +0 -0
  171. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/vsphere/common/custom_script.py +0 -0
  172. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/vsphere/common/id_generator.py +0 -0
  173. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/vsphere/common/metadata_utils.py +0 -0
  174. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/vsphere/common/service_manager.py +0 -0
  175. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/vsphere/common/service_manager_factory.py +0 -0
  176. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/vsphere/common/ssl_helper.py +0 -0
  177. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/vsphere/common/vapiconnect.py +0 -0
  178. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/vsphere/common/vim_utils.py +0 -0
  179. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/vsphere/config.py +0 -0
  180. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/vsphere/instance.py +0 -0
  181. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/provision/vsphere/vsphere_utils.py +0 -0
  182. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/resources.py +0 -0
  183. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/serve/__init__.py +0 -0
  184. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/serve/autoscalers.py +0 -0
  185. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/serve/constants.py +0 -0
  186. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/serve/controller.py +0 -0
  187. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/serve/core.py +0 -0
  188. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/serve/load_balancer.py +0 -0
  189. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/serve/load_balancing_policies.py +0 -0
  190. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/serve/replica_managers.py +0 -0
  191. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/serve/serve_state.py +0 -0
  192. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/serve/serve_utils.py +0 -0
  193. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/serve/service.py +0 -0
  194. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/serve/service_spec.py +0 -0
  195. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/setup_files/MANIFEST.in +0 -0
  196. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/setup_files/dependencies.py +0 -0
  197. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/setup_files/setup.py +0 -0
  198. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/sky_logging.py +0 -0
  199. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/skylet/LICENSE +0 -0
  200. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/skylet/__init__.py +0 -0
  201. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/skylet/attempt_skylet.py +0 -0
  202. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/skylet/autostop_lib.py +0 -0
  203. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/skylet/configs.py +0 -0
  204. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/skylet/constants.py +0 -0
  205. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/skylet/events.py +0 -0
  206. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/skylet/job_lib.py +0 -0
  207. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/skylet/log_lib.py +0 -0
  208. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/skylet/log_lib.pyi +0 -0
  209. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/skylet/providers/__init__.py +0 -0
  210. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/skylet/providers/command_runner.py +0 -0
  211. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/skylet/providers/ibm/__init__.py +0 -0
  212. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/skylet/providers/ibm/node_provider.py +0 -0
  213. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/skylet/providers/ibm/utils.py +0 -0
  214. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/skylet/providers/ibm/vpc_provider.py +0 -0
  215. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/skylet/providers/scp/__init__.py +0 -0
  216. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/skylet/providers/scp/config.py +0 -0
  217. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/skylet/providers/scp/node_provider.py +0 -0
  218. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/skylet/ray_patches/__init__.py +0 -0
  219. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/skylet/ray_patches/autoscaler.py.patch +0 -0
  220. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/skylet/ray_patches/cli.py.patch +0 -0
  221. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/skylet/ray_patches/command_runner.py.patch +0 -0
  222. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/skylet/ray_patches/log_monitor.py.patch +0 -0
  223. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/skylet/ray_patches/resource_demand_scheduler.py.patch +0 -0
  224. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/skylet/ray_patches/updater.py.patch +0 -0
  225. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/skylet/ray_patches/worker.py.patch +0 -0
  226. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/skylet/skylet.py +0 -0
  227. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/skylet/subprocess_daemon.py +0 -0
  228. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/skypilot_config.py +0 -0
  229. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/status_lib.py +0 -0
  230. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/task.py +0 -0
  231. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/templates/aws-ray.yml.j2 +0 -0
  232. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/templates/azure-ray.yml.j2 +0 -0
  233. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/templates/cudo-ray.yml.j2 +0 -0
  234. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/templates/fluidstack-ray.yml.j2 +0 -0
  235. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/templates/gcp-ray.yml.j2 +0 -0
  236. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/templates/ibm-ray.yml.j2 +0 -0
  237. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/templates/jobs-controller.yaml.j2 +0 -0
  238. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/templates/kubernetes-ingress.yml.j2 +0 -0
  239. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/templates/kubernetes-loadbalancer.yml.j2 +0 -0
  240. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/templates/kubernetes-port-forward-proxy-command.sh +0 -0
  241. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/templates/kubernetes-ssh-jump.yml.j2 +0 -0
  242. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/templates/lambda-ray.yml.j2 +0 -0
  243. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/templates/local-ray.yml.j2 +0 -0
  244. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/templates/oci-ray.yml.j2 +0 -0
  245. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/templates/paperspace-ray.yml.j2 +0 -0
  246. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/templates/runpod-ray.yml.j2 +0 -0
  247. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/templates/scp-ray.yml.j2 +0 -0
  248. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/templates/sky-serve-controller.yaml.j2 +0 -0
  249. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/templates/vsphere-ray.yml.j2 +0 -0
  250. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/usage/__init__.py +0 -0
  251. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/usage/constants.py +0 -0
  252. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/usage/usage_lib.py +0 -0
  253. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/utils/__init__.py +0 -0
  254. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/utils/accelerator_registry.py +0 -0
  255. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/utils/admin_policy_utils.py +0 -0
  256. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/utils/cli_utils/__init__.py +0 -0
  257. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/utils/cli_utils/status_utils.py +0 -0
  258. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/utils/cluster_yaml_utils.py +0 -0
  259. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/utils/command_runner.py +0 -0
  260. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/utils/command_runner.pyi +0 -0
  261. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/utils/control_master_utils.py +0 -0
  262. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/utils/controller_utils.py +0 -0
  263. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/utils/dag_utils.py +0 -0
  264. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/utils/db_utils.py +0 -0
  265. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/utils/env_options.py +0 -0
  266. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/utils/kubernetes/__init__.py +0 -0
  267. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/utils/kubernetes/create_cluster.sh +0 -0
  268. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/utils/kubernetes/delete_cluster.sh +0 -0
  269. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/utils/kubernetes/deploy_remote_cluster.sh +0 -0
  270. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/utils/kubernetes/generate_kind_config.py +0 -0
  271. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/utils/kubernetes/generate_kubeconfig.sh +0 -0
  272. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/utils/kubernetes/gpu_labeler.py +0 -0
  273. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/utils/kubernetes/k8s_gpu_labeler_job.yaml +0 -0
  274. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/utils/kubernetes/k8s_gpu_labeler_setup.yaml +0 -0
  275. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/utils/kubernetes/rsync_helper.sh +0 -0
  276. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/utils/kubernetes/ssh_jump_lifecycle_manager.py +0 -0
  277. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/utils/kubernetes_enums.py +0 -0
  278. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/utils/log_utils.py +0 -0
  279. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/utils/resources_utils.py +0 -0
  280. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/utils/rich_utils.py +0 -0
  281. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/utils/schemas.py +0 -0
  282. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/utils/subprocess_utils.py +0 -0
  283. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/utils/timeline.py +0 -0
  284. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/utils/ux_utils.py +0 -0
  285. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/sky/utils/validator.py +0 -0
  286. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/skypilot_nightly.egg-info/SOURCES.txt +0 -0
  287. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/skypilot_nightly.egg-info/dependency_links.txt +0 -0
  288. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/skypilot_nightly.egg-info/entry_points.txt +0 -0
  289. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/skypilot_nightly.egg-info/requires.txt +0 -0
  290. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/skypilot_nightly.egg-info/top_level.txt +0 -0
  291. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/tests/test_api.py +0 -0
  292. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/tests/test_cli.py +0 -0
  293. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/tests/test_config.py +0 -0
  294. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/tests/test_global_user_state.py +0 -0
  295. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/tests/test_jobs.py +0 -0
  296. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/tests/test_jobs_and_serve.py +0 -0
  297. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/tests/test_list_accelerators.py +0 -0
  298. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/tests/test_optimizer_dryruns.py +0 -0
  299. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/tests/test_optimizer_random_dag.py +0 -0
  300. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/tests/test_serve_autoscaler.py +0 -0
  301. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/tests/test_smoke.py +0 -0
  302. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/tests/test_storage.py +0 -0
  303. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/tests/test_wheels.py +0 -0
  304. {skypilot_nightly-1.0.0.dev20241204 → skypilot_nightly-1.0.0.dev20241205}/tests/test_yaml_parser.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: skypilot-nightly
3
- Version: 1.0.0.dev20241204
3
+ Version: 1.0.0.dev20241205
4
4
  Summary: SkyPilot: An intercloud broker for the clouds
5
5
  Author: SkyPilot Team
6
6
  License: Apache 2.0
@@ -5,7 +5,7 @@ from typing import Optional
5
5
  import urllib.request
6
6
 
7
7
  # Replaced with the current commit when building the wheels.
8
- _SKYPILOT_COMMIT_SHA = '51a7e177d99fdfe73a89c04dddc385940a97a37d'
8
+ _SKYPILOT_COMMIT_SHA = '6e5083293f0d9a9d069d51274c57f0e59e47e5ce'
9
9
 
10
10
 
11
11
  def _get_git_commit():
@@ -35,7 +35,7 @@ def _get_git_commit():
35
35
 
36
36
 
37
37
  __commit__ = _get_git_commit()
38
- __version__ = '1.0.0.dev20241204'
38
+ __version__ = '1.0.0.dev20241205'
39
39
  __root_dir__ = os.path.dirname(os.path.abspath(__file__))
40
40
 
41
41
 
@@ -45,20 +45,45 @@ class Backend(Generic[_ResourceHandleType]):
45
45
  @timeline.event
46
46
  @usage_lib.messages.usage.update_runtime('provision')
47
47
  def provision(
48
- self,
49
- task: 'task_lib.Task',
50
- to_provision: Optional['resources.Resources'],
51
- dryrun: bool,
52
- stream_logs: bool,
53
- cluster_name: Optional[str] = None,
54
- retry_until_up: bool = False) -> Optional[_ResourceHandleType]:
48
+ self,
49
+ task: 'task_lib.Task',
50
+ to_provision: Optional['resources.Resources'],
51
+ dryrun: bool,
52
+ stream_logs: bool,
53
+ cluster_name: Optional[str] = None,
54
+ retry_until_up: bool = False,
55
+ skip_unnecessary_provisioning: bool = False,
56
+ ) -> Optional[_ResourceHandleType]:
57
+ """Provisions resources for the given task.
58
+
59
+ Args:
60
+ task: The task to provision resources for.
61
+ to_provision: Resource config to provision. Should only be None if
62
+ cluster_name refers to an existing cluster, whose resources will
63
+ be used.
64
+ dryrun: If True, don't actually provision anything.
65
+ stream_logs: If True, stream additional logs to console.
66
+ cluster_name: Name of the cluster to provision. If None, a name will
67
+ be auto-generated. If the name refers to an existing cluster,
68
+ the existing cluster will be reused and re-provisioned.
69
+ retry_until_up: If True, retry provisioning until resources are
70
+ successfully launched.
71
+ skip_if_no_cluster_updates: If True, compare the cluster config to
72
+ the existing cluster_name's config. Skip provisioning if no
73
+ updates are needed for the existing cluster.
74
+
75
+ Returns:
76
+ A ResourceHandle object for the provisioned resources, or None if
77
+ dryrun is True.
78
+ """
55
79
  if cluster_name is None:
56
80
  cluster_name = sky.backends.backend_utils.generate_cluster_name()
57
81
  usage_lib.record_cluster_name_for_current_operation(cluster_name)
58
82
  usage_lib.messages.usage.update_actual_task(task)
59
83
  with rich_utils.safe_status(ux_utils.spinner_message('Launching')):
60
84
  return self._provision(task, to_provision, dryrun, stream_logs,
61
- cluster_name, retry_until_up)
85
+ cluster_name, retry_until_up,
86
+ skip_unnecessary_provisioning)
62
87
 
63
88
  @timeline.event
64
89
  @usage_lib.messages.usage.update_runtime('sync_workdir')
@@ -126,13 +151,15 @@ class Backend(Generic[_ResourceHandleType]):
126
151
 
127
152
  # --- Implementations of the APIs ---
128
153
  def _provision(
129
- self,
130
- task: 'task_lib.Task',
131
- to_provision: Optional['resources.Resources'],
132
- dryrun: bool,
133
- stream_logs: bool,
134
- cluster_name: str,
135
- retry_until_up: bool = False) -> Optional[_ResourceHandleType]:
154
+ self,
155
+ task: 'task_lib.Task',
156
+ to_provision: Optional['resources.Resources'],
157
+ dryrun: bool,
158
+ stream_logs: bool,
159
+ cluster_name: str,
160
+ retry_until_up: bool = False,
161
+ skip_unnecessary_provisioning: bool = False,
162
+ ) -> Optional[_ResourceHandleType]:
136
163
  raise NotImplementedError
137
164
 
138
165
  def _sync_workdir(self, handle: _ResourceHandleType, workdir: Path) -> None:
@@ -3,6 +3,7 @@ from datetime import datetime
3
3
  import enum
4
4
  import fnmatch
5
5
  import functools
6
+ import hashlib
6
7
  import os
7
8
  import pathlib
8
9
  import pprint
@@ -644,11 +645,17 @@ def write_cluster_config(
644
645
  keep_launch_fields_in_existing_config: bool = True) -> Dict[str, str]:
645
646
  """Fills in cluster configuration templates and writes them out.
646
647
 
647
- Returns: {provisioner: path to yaml, the provisioning spec}.
648
- 'provisioner' can be
649
- - 'ray'
650
- - 'tpu-create-script' (if TPU is requested)
651
- - 'tpu-delete-script' (if TPU is requested)
648
+ Returns:
649
+ Dict with the following keys:
650
+ - 'ray': Path to the generated Ray yaml config file
651
+ - 'cluster_name': Name of the cluster
652
+ - 'cluster_name_on_cloud': Name of the cluster as it appears in the
653
+ cloud provider
654
+ - 'config_hash': Hash of the cluster config and file mounts contents.
655
+ Can be missing if we unexpectedly failed to calculate the hash for
656
+ some reason. In that case we will continue without the optimization to
657
+ skip provisioning.
658
+
652
659
  Raises:
653
660
  exceptions.ResourcesUnavailableError: if the region/zones requested does
654
661
  not appear in the catalog, or an ssh_proxy_command is specified but
@@ -903,6 +910,12 @@ def write_cluster_config(
903
910
  if dryrun:
904
911
  # If dryrun, return the unfinished tmp yaml path.
905
912
  config_dict['ray'] = tmp_yaml_path
913
+ try:
914
+ config_dict['config_hash'] = _deterministic_cluster_yaml_hash(
915
+ tmp_yaml_path)
916
+ except Exception as e: # pylint: disable=broad-except
917
+ logger.warning(f'Failed to calculate config_hash: {e}')
918
+ logger.debug('Full exception:', exc_info=e)
906
919
  return config_dict
907
920
  _add_auth_to_cluster_config(cloud, tmp_yaml_path)
908
921
 
@@ -925,6 +938,17 @@ def write_cluster_config(
925
938
  yaml_config = common_utils.read_yaml(tmp_yaml_path)
926
939
  config_dict['cluster_name_on_cloud'] = yaml_config['cluster_name']
927
940
 
941
+ # Make sure to do this before we optimize file mounts. Optimization is
942
+ # non-deterministic, but everything else before this point should be
943
+ # deterministic.
944
+ try:
945
+ config_dict['config_hash'] = _deterministic_cluster_yaml_hash(
946
+ tmp_yaml_path)
947
+ except Exception as e: # pylint: disable=broad-except
948
+ logger.warning('Failed to calculate config_hash: '
949
+ f'{common_utils.format_exception(e)}')
950
+ logger.debug('Full exception:', exc_info=e)
951
+
928
952
  # Optimization: copy the contents of source files in file_mounts to a
929
953
  # special dir, and upload that as the only file_mount instead. Delay
930
954
  # calling this optimization until now, when all source files have been
@@ -1033,6 +1057,115 @@ def _count_healthy_nodes_from_ray(output: str,
1033
1057
  return ready_head, ready_workers
1034
1058
 
1035
1059
 
1060
+ @timeline.event
1061
+ def _deterministic_cluster_yaml_hash(yaml_path: str) -> str:
1062
+ """Hash the cluster yaml and contents of file mounts to a unique string.
1063
+
1064
+ Two invocations of this function should return the same string if and only
1065
+ if the contents of the yaml are the same and the file contents of all the
1066
+ file_mounts specified in the yaml are the same.
1067
+
1068
+ Limitations:
1069
+ - This function can be expensive if the file mounts are large. (E.g. a few
1070
+ seconds for ~1GB.) This should be okay since we expect that the
1071
+ file_mounts in the cluster yaml (the wheel and cloud credentials) will be
1072
+ small.
1073
+ - Symbolic links are not explicitly handled. Some symbolic link changes may
1074
+ not be detected.
1075
+
1076
+ Implementation: We create a byte sequence that captures the state of the
1077
+ yaml file and all the files in the file mounts, then hash the byte sequence.
1078
+
1079
+ The format of the byte sequence is:
1080
+ 32 bytes - sha256 hash of the yaml file
1081
+ for each file mount:
1082
+ file mount remote destination (UTF-8), \0
1083
+ if the file mount source is a file:
1084
+ 'file' encoded to UTF-8
1085
+ 32 byte sha256 hash of the file contents
1086
+ if the file mount source is a directory:
1087
+ 'dir' encoded to UTF-8
1088
+ for each directory and subdirectory withinin the file mount (starting from
1089
+ the root and descending recursively):
1090
+ name of the directory (UTF-8), \0
1091
+ name of each subdirectory within the directory (UTF-8) terminated by \0
1092
+ \0
1093
+ for each file in the directory:
1094
+ name of the file (UTF-8), \0
1095
+ 32 bytes - sha256 hash of the file contents
1096
+ \0
1097
+ if the file mount source is something else or does not exist, nothing
1098
+ \0\0
1099
+
1100
+ Rather than constructing the whole byte sequence, which may be quite large,
1101
+ we construct it incrementally by using hash.update() to add new bytes.
1102
+ """
1103
+
1104
+ def _hash_file(path: str) -> bytes:
1105
+ return common_utils.hash_file(path, 'sha256').digest()
1106
+
1107
+ config_hash = hashlib.sha256()
1108
+
1109
+ config_hash.update(_hash_file(yaml_path))
1110
+
1111
+ yaml_config = common_utils.read_yaml(yaml_path)
1112
+ file_mounts = yaml_config.get('file_mounts', {})
1113
+ # Remove the file mounts added by the newline.
1114
+ if '' in file_mounts:
1115
+ assert file_mounts[''] == '', file_mounts['']
1116
+ file_mounts.pop('')
1117
+
1118
+ for dst, src in sorted(file_mounts.items()):
1119
+ expanded_src = os.path.expanduser(src)
1120
+ config_hash.update(dst.encode('utf-8') + b'\0')
1121
+
1122
+ # If the file mount source is a symlink, this should be true. In that
1123
+ # case we hash the contents of the symlink destination.
1124
+ if os.path.isfile(expanded_src):
1125
+ config_hash.update('file'.encode('utf-8'))
1126
+ config_hash.update(_hash_file(expanded_src))
1127
+
1128
+ # This can also be a symlink to a directory. os.walk will treat it as a
1129
+ # normal directory and list the contents of the symlink destination.
1130
+ elif os.path.isdir(expanded_src):
1131
+ config_hash.update('dir'.encode('utf-8'))
1132
+
1133
+ # Aside from expanded_src, os.walk will list symlinks to directories
1134
+ # but will not recurse into them.
1135
+ for (dirpath, dirnames, filenames) in os.walk(expanded_src):
1136
+ config_hash.update(dirpath.encode('utf-8') + b'\0')
1137
+
1138
+ # Note: inplace sort will also affect the traversal order of
1139
+ # os.walk. We need it so that the os.walk order is
1140
+ # deterministic.
1141
+ dirnames.sort()
1142
+ # This includes symlinks to directories. os.walk will recurse
1143
+ # into all the directories but not the symlinks. We don't hash
1144
+ # the link destination, so if a symlink to a directory changes,
1145
+ # we won't notice.
1146
+ for dirname in dirnames:
1147
+ config_hash.update(dirname.encode('utf-8') + b'\0')
1148
+ config_hash.update(b'\0')
1149
+
1150
+ filenames.sort()
1151
+ # This includes symlinks to files. We could hash the symlink
1152
+ # destination itself but instead just hash the destination
1153
+ # contents.
1154
+ for filename in filenames:
1155
+ config_hash.update(filename.encode('utf-8') + b'\0')
1156
+ config_hash.update(
1157
+ _hash_file(os.path.join(dirpath, filename)))
1158
+ config_hash.update(b'\0')
1159
+
1160
+ else:
1161
+ logger.debug(
1162
+ f'Unexpected file_mount that is not a file or dir: {src}')
1163
+
1164
+ config_hash.update(b'\0\0')
1165
+
1166
+ return config_hash.hexdigest()
1167
+
1168
+
1036
1169
  def get_docker_user(ip: str, cluster_config_file: str) -> str:
1037
1170
  """Find docker container username."""
1038
1171
  ssh_credentials = ssh_credential_from_yaml(cluster_config_file)
@@ -1155,6 +1155,7 @@ class RetryingVmProvisioner(object):
1155
1155
  prev_cluster_status: Optional[status_lib.ClusterStatus],
1156
1156
  prev_handle: Optional['CloudVmRayResourceHandle'],
1157
1157
  prev_cluster_ever_up: bool,
1158
+ prev_config_hash: Optional[str],
1158
1159
  ) -> None:
1159
1160
  assert cluster_name is not None, 'cluster_name must be specified.'
1160
1161
  self.cluster_name = cluster_name
@@ -1163,6 +1164,7 @@ class RetryingVmProvisioner(object):
1163
1164
  self.prev_cluster_status = prev_cluster_status
1164
1165
  self.prev_handle = prev_handle
1165
1166
  self.prev_cluster_ever_up = prev_cluster_ever_up
1167
+ self.prev_config_hash = prev_config_hash
1166
1168
 
1167
1169
  def __init__(self,
1168
1170
  log_dir: str,
@@ -1324,8 +1326,21 @@ class RetryingVmProvisioner(object):
1324
1326
  prev_cluster_status: Optional[status_lib.ClusterStatus],
1325
1327
  prev_handle: Optional['CloudVmRayResourceHandle'],
1326
1328
  prev_cluster_ever_up: bool,
1329
+ skip_if_config_hash_matches: Optional[str],
1327
1330
  ) -> Dict[str, Any]:
1328
- """The provision retry loop."""
1331
+ """The provision retry loop.
1332
+
1333
+ Returns a config_dict with the following fields:
1334
+ All fields from backend_utils.write_cluster_config(). See its
1335
+ docstring.
1336
+ - 'provisioning_skipped': True if provisioning was short-circuited
1337
+ by skip_if_config_hash_matches, False otherwise.
1338
+ - 'handle': The provisioned cluster handle.
1339
+ - 'provision_record': (Only if using the new skypilot provisioner) The
1340
+ record returned by provisioner.bulk_provision().
1341
+ - 'resources_vars': (Only if using the new skypilot provisioner) The
1342
+ resources variables given by make_deploy_resources_variables().
1343
+ """
1329
1344
  # Get log_path name
1330
1345
  log_path = os.path.join(self.log_dir, 'provision.log')
1331
1346
  log_abs_path = os.path.abspath(log_path)
@@ -1434,8 +1449,18 @@ class RetryingVmProvisioner(object):
1434
1449
  raise exceptions.ResourcesUnavailableError(
1435
1450
  f'Failed to provision on cloud {to_provision.cloud} due to '
1436
1451
  f'invalid cloud config: {common_utils.format_exception(e)}')
1452
+
1453
+ if ('config_hash' in config_dict and
1454
+ skip_if_config_hash_matches == config_dict['config_hash']):
1455
+ logger.debug('Skipping provisioning of cluster with matching '
1456
+ 'config hash.')
1457
+ config_dict['provisioning_skipped'] = True
1458
+ return config_dict
1459
+ config_dict['provisioning_skipped'] = False
1460
+
1437
1461
  if dryrun:
1438
1462
  return config_dict
1463
+
1439
1464
  cluster_config_file = config_dict['ray']
1440
1465
 
1441
1466
  launched_resources = to_provision.copy(region=region.name)
@@ -1947,8 +1972,13 @@ class RetryingVmProvisioner(object):
1947
1972
  to_provision_config: ToProvisionConfig,
1948
1973
  dryrun: bool,
1949
1974
  stream_logs: bool,
1975
+ skip_unnecessary_provisioning: bool,
1950
1976
  ) -> Dict[str, Any]:
1951
- """Provision with retries for all launchable resources."""
1977
+ """Provision with retries for all launchable resources.
1978
+
1979
+ Returns the config_dict from _retry_zones() - see its docstring for
1980
+ details.
1981
+ """
1952
1982
  cluster_name = to_provision_config.cluster_name
1953
1983
  to_provision = to_provision_config.resources
1954
1984
  num_nodes = to_provision_config.num_nodes
@@ -1957,6 +1987,8 @@ class RetryingVmProvisioner(object):
1957
1987
  prev_cluster_ever_up = to_provision_config.prev_cluster_ever_up
1958
1988
  launchable_retries_disabled = (self._dag is None or
1959
1989
  self._optimize_target is None)
1990
+ skip_if_config_hash_matches = (to_provision_config.prev_config_hash if
1991
+ skip_unnecessary_provisioning else None)
1960
1992
 
1961
1993
  failover_history: List[Exception] = list()
1962
1994
 
@@ -1996,7 +2028,8 @@ class RetryingVmProvisioner(object):
1996
2028
  cloud_user_identity=cloud_user,
1997
2029
  prev_cluster_status=prev_cluster_status,
1998
2030
  prev_handle=prev_handle,
1999
- prev_cluster_ever_up=prev_cluster_ever_up)
2031
+ prev_cluster_ever_up=prev_cluster_ever_up,
2032
+ skip_if_config_hash_matches=skip_if_config_hash_matches)
2000
2033
  if dryrun:
2001
2034
  return config_dict
2002
2035
  except (exceptions.InvalidClusterNameError,
@@ -2697,14 +2730,21 @@ class CloudVmRayBackend(backends.Backend['CloudVmRayResourceHandle']):
2697
2730
  return valid_resource
2698
2731
 
2699
2732
  def _provision(
2700
- self,
2701
- task: task_lib.Task,
2702
- to_provision: Optional[resources_lib.Resources],
2703
- dryrun: bool,
2704
- stream_logs: bool,
2705
- cluster_name: str,
2706
- retry_until_up: bool = False) -> Optional[CloudVmRayResourceHandle]:
2707
- """Provisions using 'ray up'.
2733
+ self,
2734
+ task: task_lib.Task,
2735
+ to_provision: Optional[resources_lib.Resources],
2736
+ dryrun: bool,
2737
+ stream_logs: bool,
2738
+ cluster_name: str,
2739
+ retry_until_up: bool = False,
2740
+ skip_unnecessary_provisioning: bool = False,
2741
+ ) -> Optional[CloudVmRayResourceHandle]:
2742
+ """Provisions the cluster, or re-provisions an existing cluster.
2743
+
2744
+ Use the SKYPILOT provisioner if it's supported by the cloud, otherwise
2745
+ use 'ray up'.
2746
+
2747
+ See also docstring for Backend.provision().
2708
2748
 
2709
2749
  Raises:
2710
2750
  exceptions.ClusterOwnerIdentityMismatchError: if the cluster
@@ -2789,7 +2829,8 @@ class CloudVmRayBackend(backends.Backend['CloudVmRayResourceHandle']):
2789
2829
  rich_utils.force_update_status(
2790
2830
  ux_utils.spinner_message('Launching', log_path))
2791
2831
  config_dict = retry_provisioner.provision_with_retries(
2792
- task, to_provision_config, dryrun, stream_logs)
2832
+ task, to_provision_config, dryrun, stream_logs,
2833
+ skip_unnecessary_provisioning)
2793
2834
  break
2794
2835
  except exceptions.ResourcesUnavailableError as e:
2795
2836
  # Do not remove the stopped cluster from the global state
@@ -2839,11 +2880,23 @@ class CloudVmRayBackend(backends.Backend['CloudVmRayResourceHandle']):
2839
2880
  record = global_user_state.get_cluster_from_name(cluster_name)
2840
2881
  return record['handle'] if record is not None else None
2841
2882
 
2883
+ if config_dict['provisioning_skipped']:
2884
+ # Skip further provisioning.
2885
+ # In this case, we won't have certain fields in the config_dict
2886
+ # ('handle', 'provision_record', 'resources_vars')
2887
+ # We need to return the handle - but it should be the existing
2888
+ # handle for the cluster.
2889
+ record = global_user_state.get_cluster_from_name(cluster_name)
2890
+ assert record is not None and record['handle'] is not None, (
2891
+ cluster_name, record)
2892
+ return record['handle']
2893
+
2842
2894
  if 'provision_record' in config_dict:
2843
2895
  # New provisioner is used here.
2844
2896
  handle = config_dict['handle']
2845
2897
  provision_record = config_dict['provision_record']
2846
2898
  resources_vars = config_dict['resources_vars']
2899
+ config_hash = config_dict.get('config_hash', None)
2847
2900
 
2848
2901
  # Setup SkyPilot runtime after the cluster is provisioned
2849
2902
  # 1. Wait for SSH to be ready.
@@ -2878,7 +2931,7 @@ class CloudVmRayBackend(backends.Backend['CloudVmRayResourceHandle']):
2878
2931
  self._update_after_cluster_provisioned(
2879
2932
  handle, to_provision_config.prev_handle, task,
2880
2933
  prev_cluster_status, handle.external_ips(),
2881
- handle.external_ssh_ports(), lock_path)
2934
+ handle.external_ssh_ports(), lock_path, config_hash)
2882
2935
  return handle
2883
2936
 
2884
2937
  cluster_config_file = config_dict['ray']
@@ -2950,7 +3003,8 @@ class CloudVmRayBackend(backends.Backend['CloudVmRayResourceHandle']):
2950
3003
 
2951
3004
  self._update_after_cluster_provisioned(
2952
3005
  handle, to_provision_config.prev_handle, task,
2953
- prev_cluster_status, ip_list, ssh_port_list, lock_path)
3006
+ prev_cluster_status, ip_list, ssh_port_list, lock_path,
3007
+ config_hash)
2954
3008
  return handle
2955
3009
 
2956
3010
  def _open_ports(self, handle: CloudVmRayResourceHandle) -> None:
@@ -2968,8 +3022,8 @@ class CloudVmRayBackend(backends.Backend['CloudVmRayResourceHandle']):
2968
3022
  prev_handle: Optional[CloudVmRayResourceHandle],
2969
3023
  task: task_lib.Task,
2970
3024
  prev_cluster_status: Optional[status_lib.ClusterStatus],
2971
- ip_list: List[str], ssh_port_list: List[int],
2972
- lock_path: str) -> None:
3025
+ ip_list: List[str], ssh_port_list: List[int], lock_path: str,
3026
+ config_hash: str) -> None:
2973
3027
  usage_lib.messages.usage.update_cluster_resources(
2974
3028
  handle.launched_nodes, handle.launched_resources)
2975
3029
  usage_lib.messages.usage.update_final_cluster_status(
@@ -3029,6 +3083,7 @@ class CloudVmRayBackend(backends.Backend['CloudVmRayResourceHandle']):
3029
3083
  handle,
3030
3084
  set(task.resources),
3031
3085
  ready=True,
3086
+ config_hash=config_hash,
3032
3087
  )
3033
3088
  usage_lib.messages.usage.update_final_cluster_status(
3034
3089
  status_lib.ClusterStatus.UP)
@@ -4348,6 +4403,7 @@ class CloudVmRayBackend(backends.Backend['CloudVmRayResourceHandle']):
4348
4403
  # cluster is terminated (through console or auto-dwon), the record will
4349
4404
  # become None and the cluster_ever_up should be considered as False.
4350
4405
  cluster_ever_up = record is not None and record['cluster_ever_up']
4406
+ prev_config_hash = record['config_hash'] if record is not None else None
4351
4407
  logger.debug(f'cluster_ever_up: {cluster_ever_up}')
4352
4408
  logger.debug(f'record: {record}')
4353
4409
 
@@ -4386,7 +4442,8 @@ class CloudVmRayBackend(backends.Backend['CloudVmRayResourceHandle']):
4386
4442
  handle.launched_nodes,
4387
4443
  prev_cluster_status=prev_cluster_status,
4388
4444
  prev_handle=handle,
4389
- prev_cluster_ever_up=cluster_ever_up)
4445
+ prev_cluster_ever_up=cluster_ever_up,
4446
+ prev_config_hash=prev_config_hash)
4390
4447
  usage_lib.messages.usage.set_new_cluster()
4391
4448
  # Use the task_cloud, because the cloud in `to_provision` can be changed
4392
4449
  # later during the retry.
@@ -4427,7 +4484,8 @@ class CloudVmRayBackend(backends.Backend['CloudVmRayResourceHandle']):
4427
4484
  task.num_nodes,
4428
4485
  prev_cluster_status=None,
4429
4486
  prev_handle=None,
4430
- prev_cluster_ever_up=False)
4487
+ prev_cluster_ever_up=False,
4488
+ prev_config_hash=prev_config_hash)
4431
4489
 
4432
4490
  def _execute_file_mounts(self, handle: CloudVmRayResourceHandle,
4433
4491
  file_mounts: Optional[Dict[Path, Path]]):
@@ -131,13 +131,14 @@ class LocalDockerBackend(backends.Backend['LocalDockerResourceHandle']):
131
131
  pass
132
132
 
133
133
  def _provision(
134
- self,
135
- task: 'task_lib.Task',
136
- to_provision: Optional['resources.Resources'],
137
- dryrun: bool,
138
- stream_logs: bool,
139
- cluster_name: str,
140
- retry_until_up: bool = False
134
+ self,
135
+ task: 'task_lib.Task',
136
+ to_provision: Optional['resources.Resources'],
137
+ dryrun: bool,
138
+ stream_logs: bool,
139
+ cluster_name: str,
140
+ retry_until_up: bool = False,
141
+ skip_unnecessary_provisioning: bool = False,
141
142
  ) -> Optional[LocalDockerResourceHandle]:
142
143
  """Builds docker image for the task and returns cluster name as handle.
143
144
 
@@ -153,6 +154,9 @@ class LocalDockerBackend(backends.Backend['LocalDockerResourceHandle']):
153
154
  logger.warning(
154
155
  f'Retrying until up is not supported in backend: {self.NAME}. '
155
156
  'Ignored the flag.')
157
+ if skip_unnecessary_provisioning:
158
+ logger.warning(f'skip_unnecessary_provisioning is not supported in '
159
+ f'backend: {self.NAME}. Ignored the flag.')
156
160
  if stream_logs:
157
161
  logger.info(
158
162
  'Streaming build logs is not supported in LocalDockerBackend. '
@@ -15,6 +15,7 @@ from sky.adaptors import common as adaptors_common
15
15
  from sky.clouds import cloud as cloud_lib
16
16
  from sky.clouds import cloud_registry
17
17
  from sky.clouds.service_catalog import constants
18
+ from sky.utils import common_utils
18
19
  from sky.utils import rich_utils
19
20
  from sky.utils import ux_utils
20
21
 
@@ -69,8 +70,7 @@ def is_catalog_modified(filename: str) -> bool:
69
70
  meta_path = os.path.join(_ABSOLUTE_VERSIONED_CATALOG_DIR, '.meta', filename)
70
71
  md5_filepath = meta_path + '.md5'
71
72
  if os.path.exists(md5_filepath):
72
- with open(catalog_path, 'rb') as f:
73
- file_md5 = hashlib.md5(f.read()).hexdigest()
73
+ file_md5 = common_utils.hash_file(catalog_path, 'md5').hexdigest()
74
74
  with open(md5_filepath, 'r', encoding='utf-8') as f:
75
75
  last_md5 = f.read()
76
76
  return file_md5 != last_md5
@@ -108,6 +108,7 @@ def _execute(
108
108
  idle_minutes_to_autostop: Optional[int] = None,
109
109
  no_setup: bool = False,
110
110
  clone_disk_from: Optional[str] = None,
111
+ skip_unnecessary_provisioning: bool = False,
111
112
  # Internal only:
112
113
  # pylint: disable=invalid-name
113
114
  _is_launched_by_jobs_controller: bool = False,
@@ -128,8 +129,9 @@ def _execute(
128
129
  Note that if errors occur during provisioning/data syncing/setting up,
129
130
  the cluster will not be torn down for debugging purposes.
130
131
  stream_logs: bool; whether to stream all tasks' outputs to the client.
131
- handle: Optional[backends.ResourceHandle]; if provided, execution will use
132
- an existing backend cluster handle instead of provisioning a new one.
132
+ handle: Optional[backends.ResourceHandle]; if provided, execution will
133
+ attempt to use an existing backend cluster handle instead of
134
+ provisioning a new one.
133
135
  backend: Backend; backend to use for executing the tasks. Defaults to
134
136
  CloudVmRayBackend()
135
137
  retry_until_up: bool; whether to retry the provisioning until the cluster
@@ -150,6 +152,11 @@ def _execute(
150
152
  idle_minutes_to_autostop: int; if provided, the cluster will be set to
151
153
  autostop after this many minutes of idleness.
152
154
  no_setup: bool; whether to skip setup commands or not when (re-)launching.
155
+ clone_disk_from: Optional[str]; if set, clone the disk from the specified
156
+ cluster.
157
+ skip_unecessary_provisioning: bool; if True, compare the calculated
158
+ cluster config to the current cluster's config. If they match, shortcut
159
+ provisioning even if we have Stage.PROVISION.
153
160
 
154
161
  Returns:
155
162
  job_id: Optional[int]; the job ID of the submitted job. None if the
@@ -288,13 +295,18 @@ def _execute(
288
295
 
289
296
  try:
290
297
  if Stage.PROVISION in stages:
291
- if handle is None:
292
- handle = backend.provision(task,
293
- task.best_resources,
294
- dryrun=dryrun,
295
- stream_logs=stream_logs,
296
- cluster_name=cluster_name,
297
- retry_until_up=retry_until_up)
298
+ assert handle is None or skip_unnecessary_provisioning, (
299
+ 'Provisioning requested, but handle is already set. PROVISION '
300
+ 'should be excluded from stages or '
301
+ 'skip_unecessary_provisioning should be set. ')
302
+ handle = backend.provision(
303
+ task,
304
+ task.best_resources,
305
+ dryrun=dryrun,
306
+ stream_logs=stream_logs,
307
+ cluster_name=cluster_name,
308
+ retry_until_up=retry_until_up,
309
+ skip_unnecessary_provisioning=skip_unnecessary_provisioning)
298
310
 
299
311
  if handle is None:
300
312
  assert dryrun, ('If not dryrun, handle must be set or '
@@ -469,6 +481,7 @@ def launch(
469
481
 
470
482
  handle = None
471
483
  stages = None
484
+ skip_unnecessary_provisioning = False
472
485
  # Check if cluster exists and we are doing fast provisioning
473
486
  if fast and cluster_name is not None:
474
487
  cluster_status, maybe_handle = (
@@ -502,12 +515,16 @@ def launch(
502
515
  if cluster_status == status_lib.ClusterStatus.UP:
503
516
  handle = maybe_handle
504
517
  stages = [
518
+ # Provisioning will be short-circuited if the existing
519
+ # cluster config hash matches the calculated one.
520
+ Stage.PROVISION,
505
521
  Stage.SYNC_WORKDIR,
506
522
  Stage.SYNC_FILE_MOUNTS,
507
523
  Stage.PRE_EXEC,
508
524
  Stage.EXEC,
509
525
  Stage.DOWN,
510
526
  ]
527
+ skip_unnecessary_provisioning = True
511
528
 
512
529
  return _execute(
513
530
  entrypoint=entrypoint,
@@ -525,6 +542,7 @@ def launch(
525
542
  idle_minutes_to_autostop=idle_minutes_to_autostop,
526
543
  no_setup=no_setup,
527
544
  clone_disk_from=clone_disk_from,
545
+ skip_unnecessary_provisioning=skip_unnecessary_provisioning,
528
546
  _is_launched_by_jobs_controller=_is_launched_by_jobs_controller,
529
547
  _is_launched_by_sky_serve_controller=
530
548
  _is_launched_by_sky_serve_controller,