Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Schedule datastore export #3264

Merged
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
f5043d7
Sample app: schedule Datastore exports
jlara310 Mar 31, 2020
dab0a0f
Document that Scheduler encodes payload in base-64
jlara310 Apr 2, 2020
0aadf9f
Merge remote-tracking branch 'upstream/master' into schedule-datastor…
jlara310 Apr 2, 2020
abe68db
Merge branch 'master' into schedule-datastore-export
jlara310 Apr 2, 2020
2e2f7d0
Fix typo
jlara310 Apr 2, 2020
020f301
Add requirements-test.txt
jlara310 Apr 2, 2020
c344ad0
Merge branch 'master' into schedule-datastore-export
jlara310 Apr 3, 2020
93c9dfa
Merge branch 'master' into schedule-datastore-export
jlara310 Apr 7, 2020
38c50f7
Add unit tests for schedul_export Cloud Function
jlara310 Apr 9, 2020
5099c81
Merge branch 'schedule-datastore-export' of https://github.com/jlara3…
jlara310 Apr 9, 2020
d8791a5
Merge branch 'master' into schedule-datastore-export
jlara310 Apr 9, 2020
72a73d2
Remove unused imports from requirements-test.txt
jlara310 Apr 9, 2020
89c8d49
Merge branch 'master' into schedule-datastore-export
jlara310 Apr 9, 2020
aacd903
Merge branch 'master' into schedule-datastore-export
jlara310 Apr 9, 2020
306e32d
Merge branch 'master' into schedule-datastore-export
jlara310 Apr 10, 2020
5281394
Merge branch 'master' into schedule-datastore-export
jlara310 Apr 13, 2020
de03557
Merge branch 'master' into schedule-datastore-export
jlara310 Apr 14, 2020
df7aefc
Merge branch 'master' into schedule-datastore-export
jlara310 Apr 14, 2020
5ab1fa7
Merge branch 'master' into schedule-datastore-export
jlara310 Apr 14, 2020
f1984f3
Merge branch 'master' into schedule-datastore-export
jlara310 Apr 15, 2020
bc97804
Merge branch 'master' into schedule-datastore-export
jlara310 Apr 17, 2020
16383a5
Merge branch 'master' into schedule-datastore-export
jlara310 Apr 20, 2020
ca44fcc
Clean up docstring
jlara310 Apr 20, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions datastore/schedule-export/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Scheduling Datastore exports with Cloud Functions and Cloud Scheduler

This sample application demonstrates how to schedule exports of your Datastore entities. To deploy this sample, see:

[Scheduling exports](https://cloud.google.com/datastore/docs/schedule-export)
42 changes: 42 additions & 0 deletions datastore/schedule-export/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import base64
import json
import os

from googleapiclient.discovery import build

datastore = build('datastore', 'v1')
project_id = os.environ.get('GCP_PROJECT')


def datastore_export(event, context):
'''Trigger a Datastore export from a Cloud Scheduler job.
Args:
event (dict): event[data] must contain a json object encoded in
base-64. Cloud Scheduler encodes payloads in base-64 by default.
jlara310 marked this conversation as resolved.
Show resolved Hide resolved
Object must include a 'bucket' value and can include 'kinds'
and 'namespaceIds' values.
context (google.cloud.functions.Context): The Cloud Functions event
metadata.
jlara310 marked this conversation as resolved.
Show resolved Hide resolved
'''

json_data = json.loads(base64.b64decode(event['data']).decode('utf-8'))
bucket = json_data['bucket']
entity_filter = {}

if 'kinds' in json_data:
entity_filter['kinds'] = json_data['kinds']

if 'namespaceIds' in json_data:
entity_filter['namespaceIds'] = json_data['namespaceIds']

request_body = {
'outputUrlPrefix': bucket,
'entityFilter': entity_filter
}

export_request = datastore.projects().export(
projectId=project_id,
body=request_body
)
response = export_request.execute()
print(response)
3 changes: 3 additions & 0 deletions datastore/schedule-export/requirements-test.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pytest==5.3.2
gcp-devrel-py-tools==0.0.15
flaky==3.6.1
jlara310 marked this conversation as resolved.
Show resolved Hide resolved
1 change: 1 addition & 0 deletions datastore/schedule-export/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
google-api-python-client>=1.7.12
74 changes: 74 additions & 0 deletions datastore/schedule-export/schedule_export_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Copyright 2019 Google LLC All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import base64

from unittest.mock import Mock

import main

mock_context = Mock()
mock_context.event_id = '617187464135194'
mock_context.timestamp = '2020-04-15T22:09:03.761Z'


def test_datastore_export(capsys):
# Test an export without an entity filter
bucket = 'gs://my-bucket'
json_string = '{{ "bucket": "{bucket}" }}'.format(bucket=bucket)

# Encode data like Cloud Scheduler
data = bytes(json_string, 'utf-8')
data_encoded = base64.b64encode(data)
event = {"data": data_encoded}

# Mock the Datastore service
mockDatastore = Mock()
main.datastore = mockDatastore

# Call tested function
main.datastore_export(event, mock_context)
out, err = capsys.readouterr()
export_args = mockDatastore.projects().export.call_args[1]
req_body = export_args['body']
# Assert request includes test values
assert req_body['outputUrlPrefix'] == bucket


def test_datastore_export_entity_filter(capsys):
# Test an export with an entity filter
bucket = 'gs://my-bucket'
kinds = 'Users,Tasks'
namespaceIds = 'Customer831,Customer157'
json_string = '{{ "bucket": "{bucket}", "kinds": "{kinds}", "namespaceIds": "{namespaceIds}" }}'.format(
bucket=bucket, kinds=kinds, namespaceIds=namespaceIds)

# Encode data like Cloud Scheduler
data = bytes(json_string, 'utf-8')
data_encoded = base64.b64encode(data)
event = {"data": data_encoded}

# Mock the Datastore service
mockDatastore = Mock()
main.datastore = mockDatastore

# Call tested function
main.datastore_export(event, mock_context)
out, err = capsys.readouterr()
export_args = mockDatastore.projects().export.call_args[1]
req_body = export_args['body']
# Assert request includes test values
assert req_body['outputUrlPrefix'] == bucket
assert req_body['entityFilter']['kinds'] == kinds
assert req_body['entityFilter']['namespaceIds'] == namespaceIds