dsub 0.5.2__tar.gz → 0.5.4__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.
- {dsub-0.5.2/dsub.egg-info → dsub-0.5.4}/PKG-INFO +10 -9
- {dsub-0.5.2 → dsub-0.5.4}/README.md +9 -8
- {dsub-0.5.2 → dsub-0.5.4}/dsub/_dsub_version.py +1 -1
- {dsub-0.5.2 → dsub-0.5.4}/dsub/lib/param_util.py +10 -13
- {dsub-0.5.2 → dsub-0.5.4}/dsub/lib/providers_util.py +1 -1
- {dsub-0.5.2 → dsub-0.5.4}/dsub/providers/google_batch.py +12 -12
- {dsub-0.5.2 → dsub-0.5.4}/dsub/providers/google_utils.py +29 -29
- {dsub-0.5.2 → dsub-0.5.4}/dsub/providers/google_v2_base.py +4 -4
- {dsub-0.5.2 → dsub-0.5.4}/dsub/providers/local.py +43 -18
- {dsub-0.5.2 → dsub-0.5.4/dsub.egg-info}/PKG-INFO +10 -9
- {dsub-0.5.2 → dsub-0.5.4}/test/integration/e2e_after.py +1 -1
- {dsub-0.5.2 → dsub-0.5.4}/test/integration/e2e_env_list.py +1 -1
- {dsub-0.5.2 → dsub-0.5.4}/test/integration/e2e_io_tasks.py +2 -2
- {dsub-0.5.2 → dsub-0.5.4}/test/integration/test_setup_e2e.py +4 -4
- {dsub-0.5.2 → dsub-0.5.4}/test/integration/test_util.py +4 -4
- {dsub-0.5.2 → dsub-0.5.4}/LICENSE +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/MANIFEST.in +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/dsub/__init__.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/dsub/commands/__init__.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/dsub/commands/ddel.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/dsub/commands/dstat.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/dsub/commands/dsub.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/dsub/lib/__init__.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/dsub/lib/dsub_errors.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/dsub/lib/dsub_util.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/dsub/lib/job_model.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/dsub/lib/output_formatter.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/dsub/lib/resources.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/dsub/lib/retry_util.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/dsub/providers/__init__.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/dsub/providers/base.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/dsub/providers/batch_dummy.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/dsub/providers/google_base.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/dsub/providers/google_batch_operations.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/dsub/providers/google_cls_v2.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/dsub/providers/google_custom_machine.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/dsub/providers/google_v2_operations.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/dsub/providers/google_v2_pipelines.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/dsub/providers/google_v2_versions.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/dsub/providers/local/runner.sh +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/dsub/providers/provider_base.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/dsub/providers/stub.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/dsub/providers/test_fails.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/dsub.egg-info/SOURCES.txt +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/dsub.egg-info/dependency_links.txt +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/dsub.egg-info/entry_points.txt +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/dsub.egg-info/requires.txt +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/dsub.egg-info/top_level.txt +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/setup.cfg +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/setup.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/test/__init__.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/test/integration/__init__.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/test/integration/e2e_after_fail.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/test/integration/e2e_python_api.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/test/integration/get_data_value.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/test/integration/script_python.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/test/integration/test_setup.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/test/unit/__init__.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/test/unit/batch_client_test.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/test/unit/batch_handling_test.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/test/unit/custom_machine_test.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/test/unit/dstat_test.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/test/unit/dsub_test.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/test/unit/dsub_util_test.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/test/unit/fake_time.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/test/unit/fake_time_test.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/test/unit/gpu_test.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/test/unit/job_model_test.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/test/unit/local_provider_test.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/test/unit/logging_uri_test.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/test/unit/param_util_test.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/test/unit/retrying_test.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/test/unit/rfc3339_test.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/test/unit/stub_provider_test.py +0 -0
- {dsub-0.5.2 → dsub-0.5.4}/test/unit/wait_and_retry_test.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dsub
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.4
|
|
4
4
|
Summary: A command-line tool that makes it easy to submit and run batch scripts in the cloud
|
|
5
5
|
Home-page: https://github.com/DataBiosphere/dsub
|
|
6
6
|
Author: Verily
|
|
@@ -108,7 +108,7 @@ While not used directly by `dsub` for the `google-batch` provider, you are likel
|
|
|
108
108
|
Cloud SDK](https://cloud.google.com/sdk/).
|
|
109
109
|
|
|
110
110
|
If you will be using the `local` provider for faster job development,
|
|
111
|
-
you *will* need to install the Google Cloud SDK, which uses `
|
|
111
|
+
you *will* need to install the Google Cloud SDK, which uses `gcloud storage` to ensure
|
|
112
112
|
file operation semantics consistent with the Google `dsub` providers.
|
|
113
113
|
|
|
114
114
|
1. [Install the Google Cloud SDK](https://cloud.google.com/sdk/)
|
|
@@ -234,10 +234,10 @@ The steps for getting started differ slightly as indicated in the steps below:
|
|
|
234
234
|
|
|
235
235
|
The dsub logs and output files will be written to a bucket. Create a
|
|
236
236
|
bucket using the [storage browser](https://console.cloud.google.com/storage/browser?project=)
|
|
237
|
-
or run the command-line utility [
|
|
237
|
+
or run the command-line utility [gcloud storage](https://cloud.google.com/sdk/gcloud/reference/storage),
|
|
238
238
|
included in the Cloud SDK.
|
|
239
239
|
|
|
240
|
-
|
|
240
|
+
gcloud storage buckets create gs://my-bucket
|
|
241
241
|
|
|
242
242
|
Change `my-bucket` to a unique name that follows the
|
|
243
243
|
[bucket-naming conventions](https://cloud.google.com/storage/docs/bucket-naming).
|
|
@@ -267,7 +267,7 @@ The steps for getting started differ slightly as indicated in the steps below:
|
|
|
267
267
|
|
|
268
268
|
1. View the output file.
|
|
269
269
|
|
|
270
|
-
|
|
270
|
+
gcloud storage cat gs://my-bucket/output/out.txt
|
|
271
271
|
|
|
272
272
|
## Backend providers
|
|
273
273
|
|
|
@@ -403,9 +403,8 @@ by:
|
|
|
403
403
|
|
|
404
404
|
To upload the files to Google Cloud Storage, you can use the
|
|
405
405
|
[storage browser](https://console.cloud.google.com/storage/browser?project=) or
|
|
406
|
-
[
|
|
407
|
-
that’s public or shared with your service account, an email address that you
|
|
408
|
-
can find in the [Google Cloud Console](https://console.cloud.google.com).
|
|
406
|
+
[gcloud storage](https://cloud.google.com/sdk/gcloud/reference/storage).
|
|
407
|
+
You can also run on data that’s public or shared with your service account, an email address that you can find in the [Google Cloud Console](https://console.cloud.google.com).
|
|
409
408
|
|
|
410
409
|
#### Files
|
|
411
410
|
|
|
@@ -780,7 +779,9 @@ of the service account will be `sa-name@project-id.iam.gserviceaccount.com`.
|
|
|
780
779
|
|
|
781
780
|
2. Grant IAM access on buckets, etc. to the service account.
|
|
782
781
|
|
|
783
|
-
|
|
782
|
+
gcloud storage buckets add-iam-policy-binding gs://bucket-name \
|
|
783
|
+
--member=serviceAccount:sa-name@project-id.iam.gserviceaccount.com \
|
|
784
|
+
--role=roles/storage.objectAdmin
|
|
784
785
|
|
|
785
786
|
3. Update your `dsub` command to include `--service-account`
|
|
786
787
|
|
|
@@ -56,7 +56,7 @@ While not used directly by `dsub` for the `google-batch` provider, you are likel
|
|
|
56
56
|
Cloud SDK](https://cloud.google.com/sdk/).
|
|
57
57
|
|
|
58
58
|
If you will be using the `local` provider for faster job development,
|
|
59
|
-
you *will* need to install the Google Cloud SDK, which uses `
|
|
59
|
+
you *will* need to install the Google Cloud SDK, which uses `gcloud storage` to ensure
|
|
60
60
|
file operation semantics consistent with the Google `dsub` providers.
|
|
61
61
|
|
|
62
62
|
1. [Install the Google Cloud SDK](https://cloud.google.com/sdk/)
|
|
@@ -182,10 +182,10 @@ The steps for getting started differ slightly as indicated in the steps below:
|
|
|
182
182
|
|
|
183
183
|
The dsub logs and output files will be written to a bucket. Create a
|
|
184
184
|
bucket using the [storage browser](https://console.cloud.google.com/storage/browser?project=)
|
|
185
|
-
or run the command-line utility [
|
|
185
|
+
or run the command-line utility [gcloud storage](https://cloud.google.com/sdk/gcloud/reference/storage),
|
|
186
186
|
included in the Cloud SDK.
|
|
187
187
|
|
|
188
|
-
|
|
188
|
+
gcloud storage buckets create gs://my-bucket
|
|
189
189
|
|
|
190
190
|
Change `my-bucket` to a unique name that follows the
|
|
191
191
|
[bucket-naming conventions](https://cloud.google.com/storage/docs/bucket-naming).
|
|
@@ -215,7 +215,7 @@ The steps for getting started differ slightly as indicated in the steps below:
|
|
|
215
215
|
|
|
216
216
|
1. View the output file.
|
|
217
217
|
|
|
218
|
-
|
|
218
|
+
gcloud storage cat gs://my-bucket/output/out.txt
|
|
219
219
|
|
|
220
220
|
## Backend providers
|
|
221
221
|
|
|
@@ -351,9 +351,8 @@ by:
|
|
|
351
351
|
|
|
352
352
|
To upload the files to Google Cloud Storage, you can use the
|
|
353
353
|
[storage browser](https://console.cloud.google.com/storage/browser?project=) or
|
|
354
|
-
[
|
|
355
|
-
that’s public or shared with your service account, an email address that you
|
|
356
|
-
can find in the [Google Cloud Console](https://console.cloud.google.com).
|
|
354
|
+
[gcloud storage](https://cloud.google.com/sdk/gcloud/reference/storage).
|
|
355
|
+
You can also run on data that’s public or shared with your service account, an email address that you can find in the [Google Cloud Console](https://console.cloud.google.com).
|
|
357
356
|
|
|
358
357
|
#### Files
|
|
359
358
|
|
|
@@ -728,7 +727,9 @@ of the service account will be `sa-name@project-id.iam.gserviceaccount.com`.
|
|
|
728
727
|
|
|
729
728
|
2. Grant IAM access on buckets, etc. to the service account.
|
|
730
729
|
|
|
731
|
-
|
|
730
|
+
gcloud storage buckets add-iam-policy-binding gs://bucket-name \
|
|
731
|
+
--member=serviceAccount:sa-name@project-id.iam.gserviceaccount.com \
|
|
732
|
+
--role=roles/storage.objectAdmin
|
|
732
733
|
|
|
733
734
|
3. Update your `dsub` command to include `--service-account`
|
|
734
735
|
|
|
@@ -827,25 +827,22 @@ def directory_fmt(directory):
|
|
|
827
827
|
|
|
828
828
|
Multiple files copy, works as intended in all cases:
|
|
829
829
|
$ touch a.txt b.txt
|
|
830
|
-
$
|
|
831
|
-
$
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
TOTAL: 2 objects, 0 bytes (0 B)
|
|
830
|
+
$ gcloud storage cp ./*.txt gs://mybucket/text_dest
|
|
831
|
+
$ gcloud storage ls gs://mybucket/text_dest/
|
|
832
|
+
gs://mybucket/text_dest/a.txt
|
|
833
|
+
gs://mybucket/text_dest/b.txt
|
|
835
834
|
|
|
836
835
|
Single file copy fails to copy into a directory:
|
|
837
836
|
$ touch 1.bam
|
|
838
|
-
$
|
|
839
|
-
$
|
|
840
|
-
|
|
841
|
-
TOTAL: 1 objects, 0 bytes (0 B)
|
|
837
|
+
$ gcloud storage cp ./*.bam gs://mybucket/bad_dest
|
|
838
|
+
$ gcloud storage ls gs://mybucket/bad_dest
|
|
839
|
+
gs://mybucket/bad_dest
|
|
842
840
|
|
|
843
841
|
Adding a trailing forward slash fixes this:
|
|
844
842
|
$ touch my.sam
|
|
845
|
-
$
|
|
846
|
-
$
|
|
847
|
-
|
|
848
|
-
TOTAL: 1 objects, 0 bytes (0 B)
|
|
843
|
+
$ gcloud storage cp ./*.sam gs://mybucket/good_folder
|
|
844
|
+
$ gcloud storage ls gs://mybucket/good_folder
|
|
845
|
+
gs://mybucket/good_folder/my.sam
|
|
849
846
|
|
|
850
847
|
Args:
|
|
851
848
|
directory (str): a uri without an blob or file basename.
|
|
@@ -145,11 +145,11 @@ _LOG_CP = textwrap.dedent("""
|
|
|
145
145
|
"${{LOGGING_DIR}}/stderr.txt" \
|
|
146
146
|
"{user_action}"
|
|
147
147
|
|
|
148
|
-
|
|
148
|
+
gcloud_cp "${{LOGGING_DIR}}/stdout.txt" "${{STDOUT_PATH}}" "text/plain" "${{USER_PROJECT}}" &
|
|
149
149
|
STDOUT_PID=$!
|
|
150
|
-
|
|
150
|
+
gcloud_cp "${{LOGGING_DIR}}/stderr.txt" "${{STDERR_PATH}}" "text/plain" "${{USER_PROJECT}}" &
|
|
151
151
|
STDERR_PID=$!
|
|
152
|
-
|
|
152
|
+
gcloud_cp "${{LOGGING_DIR}}/log.txt" "${{LOGGING_PATH}}" "text/plain" "${{USER_PROJECT}}" &
|
|
153
153
|
LOG_PID=$!
|
|
154
154
|
|
|
155
155
|
wait "${{STDOUT_PID}}"
|
|
@@ -168,7 +168,7 @@ _FINAL_LOGGING_CMD = textwrap.dedent("""\
|
|
|
168
168
|
touch "${{LOGGING_DIR}}/.stop_logging"
|
|
169
169
|
|
|
170
170
|
{log_msg_fn}
|
|
171
|
-
{
|
|
171
|
+
{gcloud_cp_fn}
|
|
172
172
|
|
|
173
173
|
{log_cp}
|
|
174
174
|
""")
|
|
@@ -182,14 +182,14 @@ _CONTINUOUS_LOGGING_CMD = textwrap.dedent("""\
|
|
|
182
182
|
readonly LOGGING_DIR="{logging_dir}"
|
|
183
183
|
|
|
184
184
|
{log_msg_fn}
|
|
185
|
-
{
|
|
185
|
+
{gcloud_cp_fn}
|
|
186
186
|
|
|
187
187
|
# Make sure the logging work directory exists
|
|
188
188
|
mkdir -p "${{LOGGING_DIR}}"
|
|
189
189
|
|
|
190
190
|
# Prep the log filter script
|
|
191
191
|
echo "${{{log_filter_var}}}" \
|
|
192
|
-
|
|
|
192
|
+
| python3 -c '{python_decode_script}' \
|
|
193
193
|
> "{log_filter_script_path}"
|
|
194
194
|
chmod a+x "{log_filter_script_path}"
|
|
195
195
|
|
|
@@ -609,7 +609,7 @@ class GoogleBatchJobProvider(google_utils.GoogleJobProviderBase):
|
|
|
609
609
|
|
|
610
610
|
continuous_logging_cmd = _CONTINUOUS_LOGGING_CMD.format(
|
|
611
611
|
log_msg_fn=google_utils.LOG_MSG_FN,
|
|
612
|
-
|
|
612
|
+
gcloud_cp_fn=google_utils.GCLOUD_CP_FN,
|
|
613
613
|
log_filter_var=_LOG_FILTER_VAR,
|
|
614
614
|
log_filter_script_path=_LOG_FILTER_SCRIPT_PATH,
|
|
615
615
|
python_decode_script=google_utils.PYTHON_DECODE_SCRIPT,
|
|
@@ -623,7 +623,7 @@ class GoogleBatchJobProvider(google_utils.GoogleJobProviderBase):
|
|
|
623
623
|
|
|
624
624
|
logging_cmd = _FINAL_LOGGING_CMD.format(
|
|
625
625
|
log_msg_fn=google_utils.LOG_MSG_FN,
|
|
626
|
-
|
|
626
|
+
gcloud_cp_fn=google_utils.GCLOUD_CP_FN,
|
|
627
627
|
log_filter_var=_LOG_FILTER_VAR,
|
|
628
628
|
log_filter_script_path=_LOG_FILTER_SCRIPT_PATH,
|
|
629
629
|
python_decode_script=google_utils.PYTHON_DECODE_SCRIPT,
|
|
@@ -729,8 +729,8 @@ class GoogleBatchJobProvider(google_utils.GoogleJobProviderBase):
|
|
|
729
729
|
'-c',
|
|
730
730
|
google_utils.LOCALIZATION_CMD.format(
|
|
731
731
|
log_msg_fn=google_utils.LOG_MSG_FN,
|
|
732
|
-
recursive_cp_fn=google_utils.
|
|
733
|
-
cp_fn=google_utils.
|
|
732
|
+
recursive_cp_fn=google_utils.GCLOUD_RSYNC_FN,
|
|
733
|
+
cp_fn=google_utils.GCLOUD_CP_FN,
|
|
734
734
|
cp_loop=google_utils.LOCALIZATION_LOOP,
|
|
735
735
|
),
|
|
736
736
|
],
|
|
@@ -778,8 +778,8 @@ class GoogleBatchJobProvider(google_utils.GoogleJobProviderBase):
|
|
|
778
778
|
'-c',
|
|
779
779
|
google_utils.LOCALIZATION_CMD.format(
|
|
780
780
|
log_msg_fn=google_utils.LOG_MSG_FN,
|
|
781
|
-
recursive_cp_fn=google_utils.
|
|
782
|
-
cp_fn=google_utils.
|
|
781
|
+
recursive_cp_fn=google_utils.GCLOUD_RSYNC_FN,
|
|
782
|
+
cp_fn=google_utils.GCLOUD_CP_FN,
|
|
783
783
|
cp_loop=google_utils.DELOCALIZATION_LOOP,
|
|
784
784
|
),
|
|
785
785
|
],
|
|
@@ -68,9 +68,9 @@ def make_runtime_dirs_command(script_dir: str, tmp_dir: str,
|
|
|
68
68
|
# pylint: enable=g-complex-comprehension
|
|
69
69
|
|
|
70
70
|
|
|
71
|
-
# Action steps that interact with GCS need
|
|
71
|
+
# Action steps that interact with GCS need gcloud and Python.
|
|
72
72
|
# Use the 'slim' variant of the cloud-sdk image as it is much smaller.
|
|
73
|
-
CLOUD_SDK_IMAGE = 'gcr.io/google.com/cloudsdktool/cloud-sdk:
|
|
73
|
+
CLOUD_SDK_IMAGE = 'gcr.io/google.com/cloudsdktool/cloud-sdk:499.0.0-slim'
|
|
74
74
|
|
|
75
75
|
# Name of the data disk
|
|
76
76
|
DATA_DISK_NAME = 'datadisk'
|
|
@@ -94,10 +94,10 @@ LOG_MSG_FN = textwrap.dedent("""\
|
|
|
94
94
|
}
|
|
95
95
|
""")
|
|
96
96
|
|
|
97
|
-
# Define a bash function for "
|
|
97
|
+
# Define a bash function for "gcloud storage cp" to be used by the logging,
|
|
98
98
|
# localization, and delocalization actions.
|
|
99
|
-
|
|
100
|
-
function
|
|
99
|
+
GCLOUD_CP_FN = textwrap.dedent("""\
|
|
100
|
+
function gcloud_cp() {
|
|
101
101
|
local src="${1}"
|
|
102
102
|
local dst="${2}"
|
|
103
103
|
local content_type="${3}"
|
|
@@ -105,33 +105,33 @@ GSUTIL_CP_FN = textwrap.dedent("""\
|
|
|
105
105
|
|
|
106
106
|
local headers=""
|
|
107
107
|
if [[ -n "${content_type}" ]]; then
|
|
108
|
-
headers="-
|
|
108
|
+
headers="--content-type=${content_type}"
|
|
109
109
|
fi
|
|
110
110
|
|
|
111
111
|
local user_project_flag=""
|
|
112
112
|
if [[ -n "${user_project_name}" ]]; then
|
|
113
|
-
user_project_flag="-
|
|
113
|
+
user_project_flag="--billing-project=${user_project_name}"
|
|
114
114
|
fi
|
|
115
115
|
|
|
116
116
|
local attempt
|
|
117
117
|
for ((attempt = 0; attempt < 4; attempt++)); do
|
|
118
|
-
log_info "
|
|
119
|
-
if
|
|
118
|
+
log_info "gcloud storage cp --no-user-output-enabled ${headers} ${user_project_flag} \"${src}\" \"${dst}\""
|
|
119
|
+
if gcloud storage cp --no-user-output-enabled ${headers} ${user_project_flag} "${src}" "${dst}"; then
|
|
120
120
|
return
|
|
121
121
|
fi
|
|
122
122
|
if (( attempt < 3 )); then
|
|
123
|
-
log_warning "Sleeping 10s before the next attempt of failed
|
|
124
|
-
log_warning "
|
|
123
|
+
log_warning "Sleeping 10s before the next attempt of failed gcloud command"
|
|
124
|
+
log_warning "gcloud storage cp --no-user-output-enabled ${headers} ${user_project_flag} \"${src}\" \"${dst}\""
|
|
125
125
|
sleep 10s
|
|
126
126
|
fi
|
|
127
127
|
done
|
|
128
128
|
|
|
129
|
-
log_error "
|
|
129
|
+
log_error "gcloud storage cp --no-user-output-enabled ${headers} ${user_project_flag} \"${src}\" \"${dst}\""
|
|
130
130
|
exit 1
|
|
131
131
|
}
|
|
132
132
|
""")
|
|
133
133
|
|
|
134
|
-
LOG_CP_FN =
|
|
134
|
+
LOG_CP_FN = GCLOUD_CP_FN + textwrap.dedent("""\
|
|
135
135
|
|
|
136
136
|
function log_cp() {
|
|
137
137
|
local src="${1}"
|
|
@@ -144,43 +144,43 @@ LOG_CP_FN = GSUTIL_CP_FN + textwrap.dedent("""\
|
|
|
144
144
|
return
|
|
145
145
|
fi
|
|
146
146
|
|
|
147
|
-
# Copy the log files to a local temporary location so that our "
|
|
147
|
+
# Copy the log files to a local temporary location so that our "gcloud storage cp" is never
|
|
148
148
|
# executed on a file that is changing.
|
|
149
149
|
|
|
150
150
|
local tmp_path="${tmp}/$(basename ${src})"
|
|
151
151
|
cp "${src}" "${tmp_path}"
|
|
152
152
|
|
|
153
|
-
|
|
153
|
+
gcloud_cp "${tmp_path}" "${dst}" "text/plain" "${user_project_name}"
|
|
154
154
|
}
|
|
155
155
|
""")
|
|
156
156
|
|
|
157
|
-
# Define a bash function for "
|
|
157
|
+
# Define a bash function for "gcloud rsync" to be used by the logging,
|
|
158
158
|
# localization, and delocalization actions.
|
|
159
|
-
|
|
160
|
-
function
|
|
159
|
+
GCLOUD_RSYNC_FN = textwrap.dedent("""\
|
|
160
|
+
function gcloud_rsync() {
|
|
161
161
|
local src="${1}"
|
|
162
162
|
local dst="${2}"
|
|
163
163
|
local user_project_name="${3}"
|
|
164
164
|
|
|
165
165
|
local user_project_flag=""
|
|
166
166
|
if [[ -n "${user_project_name}" ]]; then
|
|
167
|
-
user_project_flag="-
|
|
167
|
+
user_project_flag="--billing-project=${user_project_name}"
|
|
168
168
|
fi
|
|
169
169
|
|
|
170
170
|
local attempt
|
|
171
171
|
for ((attempt = 0; attempt < 4; attempt++)); do
|
|
172
|
-
log_info "
|
|
173
|
-
if
|
|
172
|
+
log_info "gcloud storage rsync -r --no-user-output-enabled ${user_project_flag} \"${src}\" \"${dst}\""
|
|
173
|
+
if gcloud storage rsync -r --no-user-output-enabled ${user_project_flag} "${src}" "${dst}"; then
|
|
174
174
|
return
|
|
175
175
|
fi
|
|
176
176
|
if (( attempt < 3 )); then
|
|
177
|
-
log_warning "Sleeping 10s before the next attempt of failed
|
|
178
|
-
log_warning "
|
|
177
|
+
log_warning "Sleeping 10s before the next attempt of failed gcloud command"
|
|
178
|
+
log_warning "gcloud storage rsync -r --no-user-output-enabled ${user_project_flag} \"${src}\" \"${dst}\""
|
|
179
179
|
sleep 10s
|
|
180
180
|
fi
|
|
181
181
|
done
|
|
182
182
|
|
|
183
|
-
log_error "
|
|
183
|
+
log_error "gcloud storage rsync -r --no-user-output-enabled ${user_project_flag} \"${src}\" \"${dst}\""
|
|
184
184
|
exit 1
|
|
185
185
|
}
|
|
186
186
|
""")
|
|
@@ -198,9 +198,9 @@ LOCALIZATION_LOOP = textwrap.dedent("""\
|
|
|
198
198
|
|
|
199
199
|
log_info "Localizing ${!INPUT_VAR}"
|
|
200
200
|
if [[ "${!INPUT_RECURSIVE}" -eq "1" ]]; then
|
|
201
|
-
|
|
201
|
+
gcloud_rsync "${!INPUT_SRC}" "${!INPUT_DST}" "${USER_PROJECT}"
|
|
202
202
|
else
|
|
203
|
-
|
|
203
|
+
gcloud_cp "${!INPUT_SRC}" "${!INPUT_DST}" "" "${USER_PROJECT}"
|
|
204
204
|
fi
|
|
205
205
|
done
|
|
206
206
|
""")
|
|
@@ -218,9 +218,9 @@ DELOCALIZATION_LOOP = textwrap.dedent("""\
|
|
|
218
218
|
|
|
219
219
|
log_info "Delocalizing ${!OUTPUT_VAR}"
|
|
220
220
|
if [[ "${!OUTPUT_RECURSIVE}" -eq "1" ]]; then
|
|
221
|
-
|
|
221
|
+
gcloud_rsync "${!OUTPUT_SRC}" "${!OUTPUT_DST}" "${USER_PROJECT}"
|
|
222
222
|
else
|
|
223
|
-
|
|
223
|
+
gcloud_cp "${!OUTPUT_SRC}" "${!OUTPUT_DST}" "" "${USER_PROJECT}"
|
|
224
224
|
fi
|
|
225
225
|
done
|
|
226
226
|
""")
|
|
@@ -274,7 +274,7 @@ PREPARE_CMD = textwrap.dedent("""\
|
|
|
274
274
|
{mk_runtime_dirs}
|
|
275
275
|
|
|
276
276
|
echo "${{{script_var}}}" \
|
|
277
|
-
|
|
|
277
|
+
| python3 -c '{python_decode_script}' \
|
|
278
278
|
> "{script_path}"
|
|
279
279
|
chmod a+x "{script_path}"
|
|
280
280
|
|
|
@@ -529,8 +529,8 @@ class GoogleV2JobProviderBase(google_utils.GoogleJobProviderBase):
|
|
|
529
529
|
'-c',
|
|
530
530
|
google_utils.LOCALIZATION_CMD.format(
|
|
531
531
|
log_msg_fn=google_utils.LOG_MSG_FN,
|
|
532
|
-
recursive_cp_fn=google_utils.
|
|
533
|
-
cp_fn=google_utils.
|
|
532
|
+
recursive_cp_fn=google_utils.GCLOUD_RSYNC_FN,
|
|
533
|
+
cp_fn=google_utils.GCLOUD_CP_FN,
|
|
534
534
|
cp_loop=google_utils.LOCALIZATION_LOOP,
|
|
535
535
|
),
|
|
536
536
|
],
|
|
@@ -566,8 +566,8 @@ class GoogleV2JobProviderBase(google_utils.GoogleJobProviderBase):
|
|
|
566
566
|
'-c',
|
|
567
567
|
google_utils.LOCALIZATION_CMD.format(
|
|
568
568
|
log_msg_fn=google_utils.LOG_MSG_FN,
|
|
569
|
-
recursive_cp_fn=google_utils.
|
|
570
|
-
cp_fn=google_utils.
|
|
569
|
+
recursive_cp_fn=google_utils.GCLOUD_RSYNC_FN,
|
|
570
|
+
cp_fn=google_utils.GCLOUD_CP_FN,
|
|
571
571
|
cp_loop=google_utils.DELOCALIZATION_LOOP,
|
|
572
572
|
),
|
|
573
573
|
],
|
|
@@ -712,9 +712,9 @@ class LocalJobProvider(base.JobProvider):
|
|
|
712
712
|
elif logging_path.file_provider == job_model.P_GCS:
|
|
713
713
|
mkdir_cmd = ''
|
|
714
714
|
if user_project:
|
|
715
|
-
cp_cmd = '
|
|
715
|
+
cp_cmd = 'gcloud storage cp --billing-project={}'.format(user_project)
|
|
716
716
|
else:
|
|
717
|
-
cp_cmd = '
|
|
717
|
+
cp_cmd = 'gcloud storage cp'
|
|
718
718
|
else:
|
|
719
719
|
assert False
|
|
720
720
|
|
|
@@ -773,7 +773,7 @@ class LocalJobProvider(base.JobProvider):
|
|
|
773
773
|
return '\n'.join(provider_commands)
|
|
774
774
|
|
|
775
775
|
def _get_input_target_path(self, local_file_path):
|
|
776
|
-
"""Returns a directory or file path to be the target for "
|
|
776
|
+
"""Returns a directory or file path to be the target for "gcloud storage cp".
|
|
777
777
|
|
|
778
778
|
If the filename contains a wildcard, then the target path must
|
|
779
779
|
be a directory in order to ensure consistency whether the source pattern
|
|
@@ -784,7 +784,7 @@ class LocalJobProvider(base.JobProvider):
|
|
|
784
784
|
local_file_path: A full path terminating in a file or a file wildcard.
|
|
785
785
|
|
|
786
786
|
Returns:
|
|
787
|
-
The path to use as the "
|
|
787
|
+
The path to use as the "gcloud storage cp" target.
|
|
788
788
|
"""
|
|
789
789
|
|
|
790
790
|
path, filename = os.path.split(local_file_path)
|
|
@@ -806,21 +806,34 @@ class LocalJobProvider(base.JobProvider):
|
|
|
806
806
|
|
|
807
807
|
commands.append('mkdir -p "%s"' % os.path.dirname(local_file_path))
|
|
808
808
|
|
|
809
|
-
if i.file_provider
|
|
810
|
-
#
|
|
811
|
-
#
|
|
812
|
-
#
|
|
813
|
-
#
|
|
814
|
-
# - `cp path/* dest/` will error if "path" has subdirectories.
|
|
815
|
-
# - `cp "path/*" "dest/"` will fail (it expects wildcard expansion
|
|
816
|
-
# to come from shell).
|
|
809
|
+
if i.file_provider == job_model.P_GCS:
|
|
810
|
+
# `cp path/* dest/` will error if "path" has subdirectories, and
|
|
811
|
+
# `cp "path/*" "dest/"` will fail (it expects wildcard expansion
|
|
812
|
+
# to come from shell), so use "gcloud storage cp" instead.
|
|
817
813
|
if user_project:
|
|
818
|
-
command = '
|
|
814
|
+
command = 'gcloud storage cp --billing-project=%s "%s" "%s"' % (
|
|
819
815
|
user_project, source_file_path, dest_file_path)
|
|
820
816
|
else:
|
|
821
|
-
command = '
|
|
817
|
+
command = 'gcloud storage cp "%s" "%s"' % (source_file_path,
|
|
822
818
|
dest_file_path)
|
|
823
819
|
commands.append(command)
|
|
820
|
+
elif i.file_provider == job_model.P_LOCAL:
|
|
821
|
+
# "gcloud storage cp" does not support local-to-local copies, so use
|
|
822
|
+
# rsync (without "-r", since this path is non-recursive) instead.
|
|
823
|
+
# It matches the wildcard semantics we need: like the old "gsutil
|
|
824
|
+
# cp", it silently skips subdirectories rather than erroring like
|
|
825
|
+
# plain "cp" does. rsync does not expand a quoted wildcard itself,
|
|
826
|
+
# so for a wildcard filename, only the directory portion is quoted,
|
|
827
|
+
# leaving the wildcard for the shell to expand. A non-wildcard
|
|
828
|
+
# filename is quoted as a whole so that spaces in it are preserved
|
|
829
|
+
# as a single rsync argument.
|
|
830
|
+
source_dir, source_filename = os.path.split(source_file_path)
|
|
831
|
+
if '*' in source_filename:
|
|
832
|
+
command = 'rsync "%s"/%s "%s"' % (source_dir, source_filename,
|
|
833
|
+
dest_file_path)
|
|
834
|
+
else:
|
|
835
|
+
command = 'rsync "%s" "%s"' % (source_file_path, dest_file_path)
|
|
836
|
+
commands.append(command)
|
|
824
837
|
|
|
825
838
|
return '\n'.join(commands)
|
|
826
839
|
|
|
@@ -865,13 +878,25 @@ class LocalJobProvider(base.JobProvider):
|
|
|
865
878
|
if o.file_provider == job_model.P_LOCAL:
|
|
866
879
|
commands.append('mkdir -p "%s"' % dest_path)
|
|
867
880
|
|
|
868
|
-
|
|
869
|
-
if o.file_provider in [job_model.P_LOCAL, job_model.P_GCS]:
|
|
881
|
+
if o.file_provider == job_model.P_GCS:
|
|
870
882
|
if user_project:
|
|
871
|
-
command = '
|
|
883
|
+
command = 'gcloud storage cp --billing-project=%s "%s" "%s"' % (user_project, local_path,
|
|
872
884
|
dest_path)
|
|
873
885
|
else:
|
|
874
|
-
command = '
|
|
886
|
+
command = 'gcloud storage cp "%s" "%s"' % (local_path, dest_path)
|
|
887
|
+
commands.append(command)
|
|
888
|
+
elif o.file_provider == job_model.P_LOCAL:
|
|
889
|
+
# "gcloud storage cp" does not support local-to-local copies (see
|
|
890
|
+
# _localize_inputs_command), so use rsync instead. As there, only
|
|
891
|
+
# quote the directory portion for a wildcard filename so the shell
|
|
892
|
+
# can expand it; a non-wildcard filename is quoted as a whole so
|
|
893
|
+
# that spaces in it are preserved as a single rsync argument.
|
|
894
|
+
local_dir, local_filename = os.path.split(local_path)
|
|
895
|
+
if '*' in local_filename:
|
|
896
|
+
command = 'rsync "%s"/%s "%s"' % (local_dir, local_filename,
|
|
897
|
+
dest_path)
|
|
898
|
+
else:
|
|
899
|
+
command = 'rsync "%s" "%s"' % (local_path, dest_path)
|
|
875
900
|
commands.append(command)
|
|
876
901
|
|
|
877
902
|
return '\n'.join(commands)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dsub
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.4
|
|
4
4
|
Summary: A command-line tool that makes it easy to submit and run batch scripts in the cloud
|
|
5
5
|
Home-page: https://github.com/DataBiosphere/dsub
|
|
6
6
|
Author: Verily
|
|
@@ -108,7 +108,7 @@ While not used directly by `dsub` for the `google-batch` provider, you are likel
|
|
|
108
108
|
Cloud SDK](https://cloud.google.com/sdk/).
|
|
109
109
|
|
|
110
110
|
If you will be using the `local` provider for faster job development,
|
|
111
|
-
you *will* need to install the Google Cloud SDK, which uses `
|
|
111
|
+
you *will* need to install the Google Cloud SDK, which uses `gcloud storage` to ensure
|
|
112
112
|
file operation semantics consistent with the Google `dsub` providers.
|
|
113
113
|
|
|
114
114
|
1. [Install the Google Cloud SDK](https://cloud.google.com/sdk/)
|
|
@@ -234,10 +234,10 @@ The steps for getting started differ slightly as indicated in the steps below:
|
|
|
234
234
|
|
|
235
235
|
The dsub logs and output files will be written to a bucket. Create a
|
|
236
236
|
bucket using the [storage browser](https://console.cloud.google.com/storage/browser?project=)
|
|
237
|
-
or run the command-line utility [
|
|
237
|
+
or run the command-line utility [gcloud storage](https://cloud.google.com/sdk/gcloud/reference/storage),
|
|
238
238
|
included in the Cloud SDK.
|
|
239
239
|
|
|
240
|
-
|
|
240
|
+
gcloud storage buckets create gs://my-bucket
|
|
241
241
|
|
|
242
242
|
Change `my-bucket` to a unique name that follows the
|
|
243
243
|
[bucket-naming conventions](https://cloud.google.com/storage/docs/bucket-naming).
|
|
@@ -267,7 +267,7 @@ The steps for getting started differ slightly as indicated in the steps below:
|
|
|
267
267
|
|
|
268
268
|
1. View the output file.
|
|
269
269
|
|
|
270
|
-
|
|
270
|
+
gcloud storage cat gs://my-bucket/output/out.txt
|
|
271
271
|
|
|
272
272
|
## Backend providers
|
|
273
273
|
|
|
@@ -403,9 +403,8 @@ by:
|
|
|
403
403
|
|
|
404
404
|
To upload the files to Google Cloud Storage, you can use the
|
|
405
405
|
[storage browser](https://console.cloud.google.com/storage/browser?project=) or
|
|
406
|
-
[
|
|
407
|
-
that’s public or shared with your service account, an email address that you
|
|
408
|
-
can find in the [Google Cloud Console](https://console.cloud.google.com).
|
|
406
|
+
[gcloud storage](https://cloud.google.com/sdk/gcloud/reference/storage).
|
|
407
|
+
You can also run on data that’s public or shared with your service account, an email address that you can find in the [Google Cloud Console](https://console.cloud.google.com).
|
|
409
408
|
|
|
410
409
|
#### Files
|
|
411
410
|
|
|
@@ -780,7 +779,9 @@ of the service account will be `sa-name@project-id.iam.gserviceaccount.com`.
|
|
|
780
779
|
|
|
781
780
|
2. Grant IAM access on buckets, etc. to the service account.
|
|
782
781
|
|
|
783
|
-
|
|
782
|
+
gcloud storage buckets add-iam-policy-binding gs://bucket-name \
|
|
783
|
+
--member=serviceAccount:sa-name@project-id.iam.gserviceaccount.com \
|
|
784
|
+
--role=roles/storage.objectAdmin
|
|
784
785
|
|
|
785
786
|
3. Update your `dsub` command to include `--service-account`
|
|
786
787
|
|
|
@@ -56,7 +56,7 @@ next_job = test.run_dsub([
|
|
|
56
56
|
|
|
57
57
|
print('\nChecking output...')
|
|
58
58
|
|
|
59
|
-
RESULT = test_util.
|
|
59
|
+
RESULT = test_util.gcloud_cat(TEST_FILE_PATH_2)
|
|
60
60
|
if 'hello world' not in RESULT:
|
|
61
61
|
print('Output file does not match expected', file=sys.stderr)
|
|
62
62
|
sys.exit(1)
|
|
@@ -104,7 +104,7 @@ for i in range(TASKS_COUNT):
|
|
|
104
104
|
'--output OUTPUT_PATH')
|
|
105
105
|
OUTPUT_FILE = '%s/%s.md5' % (OUTPUT_PATH[:-len('/*.md5')],
|
|
106
106
|
os.path.basename(INPUT_BAM))
|
|
107
|
-
RESULT = test_util.
|
|
107
|
+
RESULT = test_util.gcloud_cat(OUTPUT_FILE)
|
|
108
108
|
|
|
109
109
|
if not test_util.diff(RESULT_EXPECTED.strip(), RESULT.strip()):
|
|
110
110
|
print('Output file does not match expected')
|
|
@@ -119,7 +119,7 @@ for i in range(TASKS_COUNT):
|
|
|
119
119
|
RESULT_EXPECTED = POPULATION_MD5
|
|
120
120
|
for i in range(TASKS_COUNT):
|
|
121
121
|
OUTPUT_FILE = '%s/TASK_%s.md5' % (test.OUTPUTS, (i + 1))
|
|
122
|
-
RESULT = test_util.
|
|
122
|
+
RESULT = test_util.gcloud_cat(OUTPUT_FILE)
|
|
123
123
|
|
|
124
124
|
if not test_util.diff(RESULT_EXPECTED.strip(), RESULT.strip()):
|
|
125
125
|
print('Output file does not match expected')
|
|
@@ -100,9 +100,9 @@ else:
|
|
|
100
100
|
print(" Bucket detected as: %s" % DSUB_BUCKET)
|
|
101
101
|
|
|
102
102
|
print(" Checking if bucket exists")
|
|
103
|
-
if not test_util.
|
|
103
|
+
if not test_util.gcloud_ls_check("gs://%s" % DSUB_BUCKET):
|
|
104
104
|
print("Bucket does not exist: %s" % DSUB_BUCKET, file=sys.stderr)
|
|
105
|
-
print("Create the bucket with \"
|
|
105
|
+
print("Create the bucket with \"gcloud storage buckets create\".", file=sys.stderr)
|
|
106
106
|
sys.exit(1)
|
|
107
107
|
|
|
108
108
|
# Set standard LOGGING, INPUTS, and OUTPUTS values
|
|
@@ -130,10 +130,10 @@ print("Input path: %s" % INPUTS)
|
|
|
130
130
|
print("Output path: %s" % OUTPUTS)
|
|
131
131
|
|
|
132
132
|
print(" Checking if remote test files already exists")
|
|
133
|
-
if test_util.
|
|
133
|
+
if test_util.gcloud_ls_check("%s/**" % TEST_GCS_ROOT):
|
|
134
134
|
print("Test files exist: %s" % TEST_GCS_ROOT, file=sys.stderr)
|
|
135
135
|
print("Remove contents:", file=sys.stderr)
|
|
136
|
-
print("
|
|
136
|
+
print(" gcloud storage rm %s/**" % TEST_GCS_ROOT, file=sys.stderr)
|
|
137
137
|
sys.exit(1)
|
|
138
138
|
|
|
139
139
|
if TASKS_FILE:
|
|
@@ -29,13 +29,13 @@ def to_string(stdoutbytes):
|
|
|
29
29
|
return stdoutbytes.decode(encoding)
|
|
30
30
|
|
|
31
31
|
|
|
32
|
-
def
|
|
33
|
-
return not subprocess.call('
|
|
32
|
+
def gcloud_ls_check(path):
|
|
33
|
+
return not subprocess.call('gcloud storage ls "%s" 2>/dev/null' % path, shell=True)
|
|
34
34
|
|
|
35
35
|
|
|
36
|
-
def
|
|
36
|
+
def gcloud_cat(path):
|
|
37
37
|
return to_string(
|
|
38
|
-
subprocess.check_output('
|
|
38
|
+
subprocess.check_output('gcloud storage cat "%s"' % path, shell=True))
|
|
39
39
|
|
|
40
40
|
|
|
41
41
|
def diff(str1, str2):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|