skypilot-nightly 1.0.0.dev20250304__py3-none-any.whl → 1.0.0.dev20250305__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.
- sky/__init__.py +2 -2
- sky/cli.py +1 -1
- sky/client/cli.py +1 -1
- sky/jobs/dashboard/dashboard.py +15 -25
- sky/jobs/dashboard/templates/index.html +100 -3
- {skypilot_nightly-1.0.0.dev20250304.dist-info → skypilot_nightly-1.0.0.dev20250305.dist-info}/METADATA +1 -1
- {skypilot_nightly-1.0.0.dev20250304.dist-info → skypilot_nightly-1.0.0.dev20250305.dist-info}/RECORD +11 -11
- {skypilot_nightly-1.0.0.dev20250304.dist-info → skypilot_nightly-1.0.0.dev20250305.dist-info}/LICENSE +0 -0
- {skypilot_nightly-1.0.0.dev20250304.dist-info → skypilot_nightly-1.0.0.dev20250305.dist-info}/WHEEL +0 -0
- {skypilot_nightly-1.0.0.dev20250304.dist-info → skypilot_nightly-1.0.0.dev20250305.dist-info}/entry_points.txt +0 -0
- {skypilot_nightly-1.0.0.dev20250304.dist-info → skypilot_nightly-1.0.0.dev20250305.dist-info}/top_level.txt +0 -0
sky/__init__.py
CHANGED
@@ -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 = '
|
8
|
+
_SKYPILOT_COMMIT_SHA = '296a22e868b9bdf1faccbe3effbfb858a5a05905'
|
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.
|
38
|
+
__version__ = '1.0.0.dev20250305'
|
39
39
|
__root_dir__ = os.path.dirname(os.path.abspath(__file__))
|
40
40
|
|
41
41
|
|
sky/cli.py
CHANGED
@@ -3034,7 +3034,7 @@ def _down_or_stop_clusters(
|
|
3034
3034
|
# with the termination.
|
3035
3035
|
hint_or_raise(controller_name, purge)
|
3036
3036
|
except (exceptions.ClusterOwnerIdentityMismatchError,
|
3037
|
-
RuntimeError) as e:
|
3037
|
+
exceptions.NotSupportedError, RuntimeError) as e:
|
3038
3038
|
if purge:
|
3039
3039
|
click.echo(common_utils.format_exception(e))
|
3040
3040
|
else:
|
sky/client/cli.py
CHANGED
@@ -3034,7 +3034,7 @@ def _down_or_stop_clusters(
|
|
3034
3034
|
# with the termination.
|
3035
3035
|
hint_or_raise(controller_name, purge)
|
3036
3036
|
except (exceptions.ClusterOwnerIdentityMismatchError,
|
3037
|
-
RuntimeError) as e:
|
3037
|
+
exceptions.NotSupportedError, RuntimeError) as e:
|
3038
3038
|
if purge:
|
3039
3039
|
click.echo(common_utils.format_exception(e))
|
3040
3040
|
else:
|
sky/jobs/dashboard/dashboard.py
CHANGED
@@ -62,6 +62,7 @@ class JobTableColumns(enum.IntEnum):
|
|
62
62
|
- FAILOVER (13): Job failover history
|
63
63
|
- DETAILS (14): Job details
|
64
64
|
- ACTIONS (15): Available actions column
|
65
|
+
- LOG_CONTENT (16): Log content column
|
65
66
|
"""
|
66
67
|
DROPDOWN = 0
|
67
68
|
ID = 1
|
@@ -79,13 +80,14 @@ class JobTableColumns(enum.IntEnum):
|
|
79
80
|
DETAILS = 13
|
80
81
|
FAILOVER = 14
|
81
82
|
ACTIONS = 15
|
83
|
+
LOG_CONTENT = 16
|
82
84
|
|
83
85
|
|
84
86
|
# Column headers matching the indices above
|
85
87
|
JOB_TABLE_COLUMNS = [
|
86
88
|
'', 'ID', 'Task', 'Name', 'Resources', 'Submitted', 'Total Duration',
|
87
89
|
'Job Duration', 'Status', 'Started', 'Cluster', 'Region', 'Failover',
|
88
|
-
'Recoveries', 'Details', 'Actions'
|
90
|
+
'Recoveries', 'Details', 'Actions', 'Log Content'
|
89
91
|
]
|
90
92
|
|
91
93
|
# This column is given by format_job_table but should be ignored.
|
@@ -153,14 +155,14 @@ def home():
|
|
153
155
|
status_counts[task['status'].value] += 1
|
154
156
|
|
155
157
|
# Add an empty column for the dropdown button and actions column
|
156
|
-
# Exclude SCHED. STATE
|
158
|
+
# Exclude SCHED. STATE and LOG_CONTENT columns
|
157
159
|
rows = [
|
158
160
|
[''] + row[:SCHED_STATE_COLUMN] + row[SCHED_STATE_COLUMN + 1:] +
|
159
161
|
# Add empty cell for failover and actions column
|
160
|
-
[''] + [''] for row in rows
|
162
|
+
[''] + [''] + [''] for row in rows
|
161
163
|
]
|
162
164
|
|
163
|
-
# Add log content as
|
165
|
+
# Add log content as a regular column for each job
|
164
166
|
for row in rows:
|
165
167
|
job_id = str(row[JobTableColumns.ID]).strip().replace(' ⤳', '')
|
166
168
|
if job_id and job_id != '-':
|
@@ -174,17 +176,21 @@ def home():
|
|
174
176
|
log_content = f.read()
|
175
177
|
row[JobTableColumns.FAILOVER] = _extract_launch_history(
|
176
178
|
log_content)
|
179
|
+
row[JobTableColumns.LOG_CONTENT] = log_content
|
177
180
|
else:
|
178
181
|
row[JobTableColumns.FAILOVER] = 'Log file not found'
|
182
|
+
row[JobTableColumns.LOG_CONTENT] = 'Log file not found'
|
179
183
|
except (IOError, OSError) as e:
|
180
|
-
|
181
|
-
|
184
|
+
error_msg = f'Error reading log: {str(e)}'
|
185
|
+
row[JobTableColumns.FAILOVER] = error_msg
|
186
|
+
row[JobTableColumns.LOG_CONTENT] = error_msg
|
187
|
+
else:
|
188
|
+
row[JobTableColumns.LOG_CONTENT] = ''
|
182
189
|
|
183
|
-
# Validate column count
|
184
190
|
if rows and len(rows[0]) != len(JOB_TABLE_COLUMNS):
|
185
191
|
raise RuntimeError(
|
186
192
|
f'Dashboard code and managed job queue code are out of sync. '
|
187
|
-
f'Expected {
|
193
|
+
f'Expected {JOB_TABLE_COLUMNS} columns, got {rows[0]}')
|
188
194
|
|
189
195
|
# Fix STATUS color codes: '\x1b[33mCANCELLED\x1b[0m' -> 'CANCELLED'
|
190
196
|
for row in rows:
|
@@ -208,26 +214,10 @@ def home():
|
|
208
214
|
last_updated_timestamp=timestamp,
|
209
215
|
status_values=status_values,
|
210
216
|
status_counts=status_counts,
|
217
|
+
request=flask.request,
|
211
218
|
)
|
212
219
|
return rendered_html
|
213
220
|
|
214
221
|
|
215
|
-
@app.route('/download_log/<job_id>')
|
216
|
-
def download_log(job_id):
|
217
|
-
try:
|
218
|
-
log_path = os.path.join(
|
219
|
-
os.path.expanduser(managed_job_constants.JOBS_CONTROLLER_LOGS_DIR),
|
220
|
-
f'{job_id}.log')
|
221
|
-
if not os.path.exists(log_path):
|
222
|
-
flask.abort(404)
|
223
|
-
return flask.send_file(log_path,
|
224
|
-
mimetype='text/plain',
|
225
|
-
as_attachment=True,
|
226
|
-
download_name=f'job_{job_id}.log')
|
227
|
-
except (IOError, OSError) as e:
|
228
|
-
app.logger.error(f'Error downloading log for job {job_id}: {str(e)}')
|
229
|
-
flask.abort(500)
|
230
|
-
|
231
|
-
|
232
222
|
if __name__ == '__main__':
|
233
223
|
app.run()
|
@@ -498,10 +498,10 @@
|
|
498
498
|
<td data-full-text="{{ row[13] }}">{{ row[13] }}</td> {# Details #}
|
499
499
|
<td>
|
500
500
|
{% if row[1]|string|replace(' \u21B3', '') and row[1]|string|replace(' \u21B3', '') != '-' %}
|
501
|
-
<
|
502
|
-
|
501
|
+
<button class="btn btn-sm btn-outline-secondary log-btn"
|
502
|
+
data-job-id="{{ row[1]|string|replace(' \u21B3', '') }}">
|
503
503
|
controller log
|
504
|
-
</
|
504
|
+
</button>
|
505
505
|
{% endif %}
|
506
506
|
</td>
|
507
507
|
</tr>
|
@@ -509,6 +509,41 @@
|
|
509
509
|
</tbody>
|
510
510
|
</table>
|
511
511
|
</div>
|
512
|
+
|
513
|
+
<!-- Hidden container for log content -->
|
514
|
+
<div style="display: none;">
|
515
|
+
{% for row in rows %}
|
516
|
+
{% if row[1]|string|replace(' \u21B3', '') and row[1]|string|replace(' \u21B3', '') != '-' %}
|
517
|
+
<pre id="log-content-{{ row[1]|string|replace(' \u21B3', '') }}">{{ row[-1]|e }}</pre>
|
518
|
+
{% endif %}
|
519
|
+
{% endfor %}
|
520
|
+
</div>
|
521
|
+
|
522
|
+
<!-- Log Modal -->
|
523
|
+
<div class="modal fade" id="logModal" tabindex="-1" aria-labelledby="logModalLabel" aria-hidden="true">
|
524
|
+
<div class="modal-dialog modal-dialog-centered modal-lg">
|
525
|
+
<div class="modal-content">
|
526
|
+
<div class="modal-header">
|
527
|
+
<h5 class="modal-title" id="logModalLabel">Controller Log</h5>
|
528
|
+
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
529
|
+
</div>
|
530
|
+
<div class="modal-body">
|
531
|
+
<div id="logContent" style="white-space: pre-wrap; font-family: monospace; max-height: 70vh; overflow-y: auto; font-size: 0.85rem;"></div>
|
532
|
+
<div id="logError" class="alert alert-danger d-none">
|
533
|
+
Error loading log content. Please try again.
|
534
|
+
</div>
|
535
|
+
</div>
|
536
|
+
<div class="modal-footer">
|
537
|
+
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
538
|
+
<a id="downloadLogBtn" href="#" class="btn btn-primary" download>Download</a>
|
539
|
+
</div>
|
540
|
+
</div>
|
541
|
+
</div>
|
542
|
+
</div>
|
543
|
+
|
544
|
+
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"
|
545
|
+
integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4"
|
546
|
+
crossorigin="anonymous"></script>
|
512
547
|
<script>
|
513
548
|
// Folder toggle for pipelines, this will fold/unfold the rows for
|
514
549
|
// a pipeline and its tasks.
|
@@ -729,6 +764,68 @@
|
|
729
764
|
});
|
730
765
|
});
|
731
766
|
</script>
|
767
|
+
<script>
|
768
|
+
// Function to show log modal and display pre-loaded log content
|
769
|
+
function showLogModal(jobId, logContent) {
|
770
|
+
try {
|
771
|
+
// Initialize modal
|
772
|
+
const logModal = new bootstrap.Modal(document.getElementById('logModal'));
|
773
|
+
const logContentEl = document.getElementById('logContent');
|
774
|
+
const logError = document.getElementById('logError');
|
775
|
+
const downloadBtn = document.getElementById('downloadLogBtn');
|
776
|
+
|
777
|
+
// Create a Blob for download functionality
|
778
|
+
const blob = new Blob([logContent], { type: 'text/plain' });
|
779
|
+
const url = URL.createObjectURL(blob);
|
780
|
+
|
781
|
+
// Set download button href
|
782
|
+
downloadBtn.href = url;
|
783
|
+
downloadBtn.setAttribute('download', `job_${jobId}.log`);
|
784
|
+
|
785
|
+
// Clear previous content and show new content directly
|
786
|
+
logContentEl.textContent = logContent || 'No log content available';
|
787
|
+
logError.classList.add('d-none');
|
788
|
+
|
789
|
+
// Set modal title
|
790
|
+
document.getElementById('logModalLabel').textContent = `Controller Log - Job ${jobId}`;
|
791
|
+
|
792
|
+
// Show modal
|
793
|
+
logModal.show();
|
794
|
+
|
795
|
+
// Cleanup the URL object when the modal is hidden
|
796
|
+
document.getElementById('logModal').addEventListener('hidden.bs.modal', function() {
|
797
|
+
URL.revokeObjectURL(url);
|
798
|
+
}, { once: true });
|
799
|
+
} catch (error) {
|
800
|
+
console.error('Error showing log modal:', error);
|
801
|
+
document.getElementById('logError').classList.remove('d-none');
|
802
|
+
document.getElementById('logError').textContent = `Error showing log: ${error.message}`;
|
803
|
+
}
|
804
|
+
}
|
805
|
+
|
806
|
+
// Add event listeners for log buttons
|
807
|
+
document.addEventListener('DOMContentLoaded', function() {
|
808
|
+
document.addEventListener('click', function(event) {
|
809
|
+
if (event.target.closest('.log-btn')) {
|
810
|
+
try {
|
811
|
+
const button = event.target.closest('.log-btn');
|
812
|
+
const jobId = button.dataset.jobId;
|
813
|
+
const logContentEl = document.getElementById(`log-content-${jobId}`);
|
814
|
+
|
815
|
+
if (!logContentEl) {
|
816
|
+
throw new Error(`Log content element not found for job ${jobId}`);
|
817
|
+
}
|
818
|
+
|
819
|
+
const logContent = logContentEl.textContent;
|
820
|
+
showLogModal(jobId, logContent);
|
821
|
+
} catch (error) {
|
822
|
+
console.error('Error getting log content:', error);
|
823
|
+
showLogModal(jobId, `Error loading log: ${error.message}`);
|
824
|
+
}
|
825
|
+
}
|
826
|
+
});
|
827
|
+
});
|
828
|
+
</script>
|
732
829
|
</body>
|
733
830
|
|
734
831
|
</html>
|
{skypilot_nightly-1.0.0.dev20250304.dist-info → skypilot_nightly-1.0.0.dev20250305.dist-info}/RECORD
RENAMED
@@ -1,8 +1,8 @@
|
|
1
|
-
sky/__init__.py,sha256=
|
1
|
+
sky/__init__.py,sha256=jx4qQ0KP5eTx7b33ZojeC61vkrA5H7sULXcKLW-vL00,6428
|
2
2
|
sky/admin_policy.py,sha256=hPo02f_A32gCqhUueF0QYy1fMSSKqRwYEg_9FxScN_s,3248
|
3
3
|
sky/authentication.py,sha256=hCEqi77nprQEg3ktfRL51xiiw16zwZOmFEDB_Z7fWVU,22384
|
4
4
|
sky/check.py,sha256=NDKx_Zm7YRxPjMv82wz3ESLnGIPljaACyqVdVNM0PzY,11258
|
5
|
-
sky/cli.py,sha256=
|
5
|
+
sky/cli.py,sha256=ditGQ-K92yDT_f3a4xqjcqTU1ql33BE4uIy-ArX3BV0,221499
|
6
6
|
sky/cloud_stores.py,sha256=kEHXd2divyra-1c3EusHxKyM5yTQlTXc6cKVXofsefA,23978
|
7
7
|
sky/core.py,sha256=MU9hcTdh8baMGrr2ZXmbxx12vNlhajrkeyg5QtV717c,47609
|
8
8
|
sky/dag.py,sha256=Yl7Ry26Vql5cv4YMz8g9kOUgtoCihJnw7c8NgZYakMY,3242
|
@@ -43,7 +43,7 @@ sky/benchmark/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
43
43
|
sky/benchmark/benchmark_state.py,sha256=X8CXmuU9KgsDRhKedhFgjeRMUFWtQsjFs1qECvPG2yg,8723
|
44
44
|
sky/benchmark/benchmark_utils.py,sha256=o4RymqSceq5mLEZL0upQM6NVEzJJQzj9s9tTm49uUTc,26365
|
45
45
|
sky/client/__init__.py,sha256=pz6xvVSd9X-gwqbsDL0E9QOojYqM0KAD0j-NCyCIF1k,38
|
46
|
-
sky/client/cli.py,sha256=
|
46
|
+
sky/client/cli.py,sha256=ditGQ-K92yDT_f3a4xqjcqTU1ql33BE4uIy-ArX3BV0,221499
|
47
47
|
sky/client/common.py,sha256=axDic7WOG1e78SdFm5XIwdhX7YNvf3g4k7INrsW3X4s,14611
|
48
48
|
sky/client/sdk.py,sha256=IRx72BXqOn_WVvtOuTXfgR5zcSm_lyoXeYxa5c_2_qk,68723
|
49
49
|
sky/clouds/__init__.py,sha256=OW6mJ-9hpJSBORCgt2LippLQEYZHNfnBW1mooRNNvxo,1416
|
@@ -115,9 +115,9 @@ sky/jobs/state.py,sha256=tDULLH6DVs4oKUIKhh0UAn3RzyVGuIUtEq5kW7K1Ojw,44585
|
|
115
115
|
sky/jobs/utils.py,sha256=O1cOXeWXzZNxQzEZ4xwadskQr1Azm1pCRe4Ju0dfvfg,55845
|
116
116
|
sky/jobs/client/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
117
117
|
sky/jobs/client/sdk.py,sha256=4STtriCWLUq1mm-tEsh_iXC7r-U7_PY0R9X6-DNpaXs,10122
|
118
|
-
sky/jobs/dashboard/dashboard.py,sha256=
|
118
|
+
sky/jobs/dashboard/dashboard.py,sha256=JKg8cCH_Y0sf3MoDTx85BghVEXWpp8ItPLshp09-_Js,7618
|
119
119
|
sky/jobs/dashboard/static/favicon.ico,sha256=uYlvgxSM7gjBmXpZ8wydvZUPAbJiiix-rc2Xe5mma9s,15086
|
120
|
-
sky/jobs/dashboard/templates/index.html,sha256=
|
120
|
+
sky/jobs/dashboard/templates/index.html,sha256=NrlTDiEHJDt7sViwWgXUSxVCyVl_IEukE5jdvN8WhtQ,33132
|
121
121
|
sky/jobs/server/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
122
122
|
sky/jobs/server/core.py,sha256=s6A3KJsSQz1GlD6qfJ-XiEg6scc3sqMTqVd1Kr6ZTIU,25113
|
123
123
|
sky/jobs/server/dashboard_utils.py,sha256=2Mbx40W1pQqPEPHsSDbHeaF0j5cgyKy-_A9Owdwp_AQ,2315
|
@@ -344,9 +344,9 @@ sky/utils/kubernetes/k8s_gpu_labeler_setup.yaml,sha256=VLKT2KKimZu1GDg_4AIlIt488
|
|
344
344
|
sky/utils/kubernetes/kubernetes_deploy_utils.py,sha256=otzHzpliHDCpzYT-nU9Q0ZExbiFpDPWvhxwkvchZj7k,10073
|
345
345
|
sky/utils/kubernetes/rsync_helper.sh,sha256=h4YwrPFf9727CACnMJvF3EyK_0OeOYKKt4su_daKekw,1256
|
346
346
|
sky/utils/kubernetes/ssh_jump_lifecycle_manager.py,sha256=Kq1MDygF2IxFmu9FXpCxqucXLmeUrvs6OtRij6XTQbo,6554
|
347
|
-
skypilot_nightly-1.0.0.
|
348
|
-
skypilot_nightly-1.0.0.
|
349
|
-
skypilot_nightly-1.0.0.
|
350
|
-
skypilot_nightly-1.0.0.
|
351
|
-
skypilot_nightly-1.0.0.
|
352
|
-
skypilot_nightly-1.0.0.
|
347
|
+
skypilot_nightly-1.0.0.dev20250305.dist-info/LICENSE,sha256=emRJAvE7ngL6x0RhQvlns5wJzGI3NEQ_WMjNmd9TZc4,12170
|
348
|
+
skypilot_nightly-1.0.0.dev20250305.dist-info/METADATA,sha256=lAGzKAGmMJRgwB6StfHToB5grjGmOXSeJVWQbdYGkhM,18173
|
349
|
+
skypilot_nightly-1.0.0.dev20250305.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
|
350
|
+
skypilot_nightly-1.0.0.dev20250305.dist-info/entry_points.txt,sha256=StA6HYpuHj-Y61L2Ze-hK2IcLWgLZcML5gJu8cs6nU4,36
|
351
|
+
skypilot_nightly-1.0.0.dev20250305.dist-info/top_level.txt,sha256=qA8QuiNNb6Y1OF-pCUtPEr6sLEwy2xJX06Bd_CrtrHY,4
|
352
|
+
skypilot_nightly-1.0.0.dev20250305.dist-info/RECORD,,
|
File without changes
|
{skypilot_nightly-1.0.0.dev20250304.dist-info → skypilot_nightly-1.0.0.dev20250305.dist-info}/WHEEL
RENAMED
File without changes
|
File without changes
|
File without changes
|