Skip to content
This repository was archived by the owner on Sep 5, 2023. It is now read-only.

Commit af33ed9

Browse files
authored
docs(samples): Adding sample for bucket mounting (#43)
* docs(samples): Adding sample for bucket mounting * Fixing lint stuff.
1 parent 860c9f3 commit af33ed9

File tree

4 files changed

+166
-2
lines changed

4 files changed

+166
-2
lines changed

samples/requirements-test.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
pytest==7.1.3
22
pytest-parallel==0.1.1
3+
google-cloud-storage==2.5.0
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# Copyright 2022 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
# [START batch_create_script_job_with_bucket]
16+
from google.cloud import batch_v1
17+
18+
19+
def create_script_job_with_bucket(project_id: str, region: str, job_name: str, bucket_name: str) -> batch_v1.Job:
20+
"""
21+
This method shows how to create a sample Batch Job that will run
22+
a simple command on Cloud Compute instances.
23+
24+
Args:
25+
project_id: project ID or project number of the Cloud project you want to use.
26+
region: name of the region you want to use to run the job. Regions that are
27+
available for Batch are listed on: https://cloud.google.com/batch/docs/get-started#locations
28+
job_name: the name of the job that will be created.
29+
It needs to be unique for each project and region pair.
30+
bucket_name: name of the bucket to be mounted for your Job.
31+
32+
Returns:
33+
A job object representing the job created.
34+
"""
35+
client = batch_v1.BatchServiceClient()
36+
37+
# Define what will be done as part of the job.
38+
task = batch_v1.TaskSpec()
39+
runnable = batch_v1.Runnable()
40+
runnable.script = batch_v1.Runnable.Script()
41+
runnable.script.text = "echo Hello world from task ${BATCH_TASK_INDEX}. >> /mnt/share/output_task_${BATCH_TASK_INDEX}.txt"
42+
task.runnables = [runnable]
43+
44+
gcs_bucket = batch_v1.GCS()
45+
gcs_bucket.remote_path = bucket_name
46+
gcs_volume = batch_v1.Volume()
47+
gcs_volume.gcs = gcs_bucket
48+
gcs_volume.mount_path = '/mnt/share'
49+
task.volumes = [gcs_volume]
50+
51+
# We can specify what resources are requested by each task.
52+
resources = batch_v1.ComputeResource()
53+
resources.cpu_milli = 500 # in milliseconds per cpu-second. This means the task requires 50% of a single CPUs.
54+
resources.memory_mib = 16
55+
task.compute_resource = resources
56+
57+
task.max_retry_count = 2
58+
task.max_run_duration = "3600s"
59+
60+
# Tasks are grouped inside a job using TaskGroups.
61+
group = batch_v1.TaskGroup()
62+
group.task_count = 4
63+
group.task_spec = task
64+
65+
# Policies are used to define on what kind of virtual machines the tasks will run on.
66+
# In this case, we tell the system to use "e2-standard-4" machine type.
67+
# Read more about machine types here: https://cloud.google.com/compute/docs/machine-types
68+
allocation_policy = batch_v1.AllocationPolicy()
69+
policy = batch_v1.AllocationPolicy.InstancePolicy()
70+
policy.machine_type = "e2-standard-4"
71+
instances = batch_v1.AllocationPolicy.InstancePolicyOrTemplate()
72+
instances.policy = policy
73+
allocation_policy.instances = [instances]
74+
75+
job = batch_v1.Job()
76+
job.task_groups = [group]
77+
job.allocation_policy = allocation_policy
78+
job.labels = {"env": "testing", "type": "script", "mount": "bucket"}
79+
# We use Cloud Logging as it's an out of the box available option
80+
job.logs_policy = batch_v1.LogsPolicy()
81+
job.logs_policy.destination = batch_v1.LogsPolicy.Destination.CLOUD_LOGGING
82+
83+
create_request = batch_v1.CreateJobRequest()
84+
create_request.job = job
85+
create_request.job_id = job_name
86+
# The job's parent is the region in which the job will run
87+
create_request.parent = f"projects/{project_id}/locations/{region}"
88+
89+
return client.create_job(create_request)
90+
# [END batch_create_script_job_with_bucket]

samples/snippets/tests/test_basics.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414
import time
15+
from typing import Callable
1516
import uuid
1617

17-
1818
import google.auth
1919
from google.cloud import batch_v1
2020
import pytest
@@ -44,7 +44,7 @@ def job_name():
4444
return f"test-job-{uuid.uuid4().hex[:10]}"
4545

4646

47-
def _test_body(test_job: batch_v1.Job):
47+
def _test_body(test_job: batch_v1.Job, additional_test: Callable = None):
4848
start_time = time.time()
4949
try:
5050
while test_job.status.state in WAIT_STATES:
@@ -61,6 +61,9 @@ def _test_body(test_job: batch_v1.Job):
6161
break
6262
else:
6363
pytest.fail(f"Couldn't find job {test_job.uid} on the list of jobs.")
64+
65+
if additional_test:
66+
additional_test()
6467
finally:
6568
delete_job(PROJECT, REGION, test_job.name.rsplit('/', maxsplit=1)[1]).result()
6669

samples/snippets/tests/test_bucket.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# Copyright 2022 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
import uuid
15+
16+
17+
import google.auth
18+
from google.cloud import batch_v1
19+
from google.cloud import storage
20+
import pytest
21+
22+
from .test_basics import _test_body
23+
from ..create.create_with_mounted_bucket import create_script_job_with_bucket
24+
25+
PROJECT = google.auth.default()[1]
26+
REGION = 'europe-north1'
27+
28+
TIMEOUT = 600 # 10 minutes
29+
30+
WAIT_STATES = {
31+
batch_v1.JobStatus.State.STATE_UNSPECIFIED,
32+
batch_v1.JobStatus.State.QUEUED,
33+
batch_v1.JobStatus.State.RUNNING,
34+
batch_v1.JobStatus.State.SCHEDULED,
35+
}
36+
37+
38+
@pytest.fixture
39+
def job_name():
40+
return f"test-job-{uuid.uuid4().hex[:10]}"
41+
42+
43+
@pytest.fixture()
44+
def test_bucket():
45+
bucket_name = f"test-bucket-{uuid.uuid4().hex[:8]}"
46+
client = storage.Client()
47+
client.create_bucket(bucket_name, location="eu")
48+
49+
yield bucket_name
50+
51+
bucket = client.get_bucket(bucket_name)
52+
bucket.delete(force=True)
53+
54+
55+
def _test_bucket_content(test_bucket):
56+
client = storage.Client()
57+
bucket = client.get_bucket(test_bucket)
58+
59+
file_name_template = "output_task_{task_number}.txt"
60+
file_content_template = "Hello world from task {task_number}.\n"
61+
62+
for i in range(4):
63+
blob = bucket.blob(file_name_template.format(task_number=i))
64+
content = blob.download_as_bytes().decode()
65+
assert content == file_content_template.format(task_number=i)
66+
67+
68+
def test_bucket_job(job_name, test_bucket):
69+
job = create_script_job_with_bucket(PROJECT, REGION, job_name, test_bucket)
70+
_test_body(job, lambda: _test_bucket_content(test_bucket))

0 commit comments

Comments
 (0)