diff --git a/bigtable/hello/README.md b/bigtable/hello/README.md new file mode 100644 index 00000000000..ade60661121 --- /dev/null +++ b/bigtable/hello/README.md @@ -0,0 +1,42 @@ +# Cloud Bigtable Hello World + +This is a simple application that demonstrates using the [Google Cloud Client +Library][gcloud-python] to connect to and interact with Cloud Bigtable. + +[gcloud-python]: https://github.com/GoogleCloudPlatform/gcloud-python + + +## Provision a cluster + +Follow the instructions in the [user documentation](https://cloud.google.com/bigtable/docs/creating-cluster) +to create a Google Cloud Platform project and Cloud Bigtable cluster if necessary. +You'll need to reference your project ID, zone and cluster ID to run the application. + + +## Run the application + +First, set your [Google Application Default Credentials](https://developers.google.com/identity/protocols/application-default-credentials) + +Install the dependencies with pip. + +``` +$ pip install -r requirements.txt +``` + +Run the application. Replace the command-line parameters with values for your cluster. + +``` +$ python main.py my-project my-cluster us-central1-c +``` + +You will see output resembling the following: + +``` +Create table Hello-Bigtable-1234 +Write some greetings to the table +Scan for all greetings: + greeting0: Hello World! + greeting1: Hello Cloud Bigtable! + greeting2: Hello HappyBase! +Delete table Hello-Bigtable-1234 +``` diff --git a/bigtable/hello/main.py b/bigtable/hello/main.py new file mode 100644 index 00000000000..458534965d2 --- /dev/null +++ b/bigtable/hello/main.py @@ -0,0 +1,119 @@ +#!/usr/bin/env python + +# Copyright 2016 Google Inc. +# +# 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. + +"""Demonstrates how to connect to Cloud Bigtable and run some basic operations. + +Prerequisites: + +- Create a Cloud Bigtable cluster. + https://cloud.google.com/bigtable/docs/creating-cluster +- Set your Google Application Default Credentials. + https://developers.google.com/identity/protocols/application-default-credentials +""" + +import argparse + +from gcloud import bigtable + + +def main(project_id, cluster_id, zone, table_id): + # [START connecting_to_bigtable] + # The client must be created with admin=True because it will create a + # table. + with bigtable.Client(project=project_id, admin=True) as client: + cluster = client.cluster(zone, cluster_id) + # [END connecting_to_bigtable] + + # [START creating_a_table] + print('Creating the {} table.'.format(table_id)) + table = cluster.table(table_id) + table.create() + column_family_id = 'cf1' + cf1 = table.column_family(column_family_id) + cf1.create() + # [END creating_a_table] + + # [START writing_rows] + print('Writing some greetings to the table.') + column_id = 'greeting'.encode('utf-8') + greetings = [ + 'Hello World!', + 'Hello Cloud Bigtable!', + 'Hello Python!', + ] + + for i, value in enumerate(greetings): + # Note: This example uses sequential numeric IDs for simplicity, + # but this can result in poor performance in a production + # application. Since rows are stored in sorted order by key, + # sequential keys can result in poor distribution of operations + # across nodes. + # + # For more information about how to design a Bigtable schema for + # the best performance, see the documentation: + # + # https://cloud.google.com/bigtable/docs/schema-design + row_key = 'greeting{}'.format(i) + row = table.row(row_key) + row.set_cell( + column_family_id, + column_id.encode('utf-8'), + value.encode('utf-8')) + row.commit() + # [END writing_rows] + + # [START getting_a_row] + print('Getting a single greeting by row key.') + key = 'greeting0' + row = table.read_row(key.encode('utf-8')) + value = row.cells[column_family_id][column_id.encode('utf-8')][0].value + print('\t{}: {}'.format(key, value.decode('utf-8'))) + # [END getting_a_row] + + # [START scanning_all_rows] + print('Scanning for all greetings:') + partial_rows = table.read_rows() + partial_rows.consume_all() + + for row_key, row in partial_rows.rows.items(): + key = row_key.decode('utf-8') + cell = row.cells[column_family_id][column_id.encode('utf-8')][0] + value = cell.value.decode('utf-8') + print('\t{}: {}'.format(key, value)) + # [END scanning_all_rows] + + # [START deleting_a_table] + print('Deleting the {} table.'.format(table_id)) + table.delete() + # [END deleting_a_table] + + +if __name__ == '__main__': + parser = argparse.ArgumentParser( + description=__doc__, + formatter_class=argparse.ArgumentDefaultsHelpFormatter) + parser.add_argument('project_id', help='Your Cloud Platform project ID.') + parser.add_argument( + 'cluster', help='ID of the Cloud Bigtable cluster to connect to.') + parser.add_argument( + 'zone', help='Zone that contains the Cloud Bigtable cluster.') + parser.add_argument( + '--table', + help='Table to create and destroy.', + default='Hello-Bigtable') + + args = parser.parse_args() + main(args.project_id, args.cluster, args.zone, args.table) diff --git a/bigtable/hello/main_test.py b/bigtable/hello/main_test.py new file mode 100644 index 00000000000..581d10a0471 --- /dev/null +++ b/bigtable/hello/main_test.py @@ -0,0 +1,49 @@ +# Copyright 2016 Google Inc. +# +# 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 random +import re +import sys + +from main import main + +import pytest + +TABLE_NAME_FORMAT = 'Hello-Bigtable-{}' +TABLE_NAME_RANGE = 10000 + + +@pytest.mark.skipif( + sys.version_info >= (3, 0), + reason=("grpc doesn't yet support python3 " + 'https://github.com/grpc/grpc/issues/282')) +def test_main(cloud_config, capsys): + table_name = TABLE_NAME_FORMAT.format( + random.randrange(TABLE_NAME_RANGE)) + main( + cloud_config.project, + cloud_config.bigtable_cluster, + cloud_config.bigtable_zone, + table_name) + + out, _ = capsys.readouterr() + assert re.search( + re.compile(r'Creating the Hello-Bigtable-[0-9]+ table\.'), out) + assert re.search(re.compile(r'Writing some greetings to the table\.'), out) + assert re.search(re.compile(r'Getting a single greeting by row key.'), out) + assert re.search(re.compile(r'greeting0: Hello World!'), out) + assert re.search(re.compile(r'Scanning for all greetings'), out) + assert re.search(re.compile(r'greeting1: Hello Cloud Bigtable!'), out) + assert re.search( + re.compile(r'Deleting the Hello-Bigtable-[0-9]+ table\.'), out) diff --git a/bigtable/hello/requirements.txt b/bigtable/hello/requirements.txt new file mode 100644 index 00000000000..5cb34f73a1c --- /dev/null +++ b/bigtable/hello/requirements.txt @@ -0,0 +1 @@ +gcloud[grpc]==0.16.0 diff --git a/bigtable/hello_happybase/README.md b/bigtable/hello_happybase/README.md index 6fc0473a33d..910aab6f59e 100644 --- a/bigtable/hello_happybase/README.md +++ b/bigtable/hello_happybase/README.md @@ -1,4 +1,4 @@ -# Cloud Bigtable Hello World +# Cloud Bigtable Hello World (HappyBase) This is a simple application that demonstrates using the [Google Cloud Client Library][gcloud-python] to connect to and interact with Cloud Bigtable. diff --git a/bigtable/hello_happybase/main.py b/bigtable/hello_happybase/main.py index fc6ff6bb1e3..8686a1b43f0 100644 --- a/bigtable/hello_happybase/main.py +++ b/bigtable/hello_happybase/main.py @@ -22,8 +22,6 @@ https://cloud.google.com/bigtable/docs/creating-cluster - Set your Google Application Default Credentials. https://developers.google.com/identity/protocols/application-default-credentials -- Set the GCLOUD_PROJECT environment variable to your project ID. - https://support.google.com/cloud/answer/6158840 """ import argparse @@ -61,6 +59,7 @@ def main(project_id, cluster_id, zone, table_name): 'Hello Cloud Bigtable!', 'Hello HappyBase!', ] + for i, value in enumerate(greetings): # Note: This example uses sequential numeric IDs for simplicity, # but this can result in poor performance in a production @@ -85,6 +84,7 @@ def main(project_id, cluster_id, zone, table_name): # [START scanning_all_rows] print('Scanning for all greetings:') + for key, row in table.scan(): print('\t{}: {}'.format(key, row[column_name])) # [END scanning_all_rows] @@ -93,19 +93,16 @@ def main(project_id, cluster_id, zone, table_name): print('Deleting the {} table.'.format(table_name)) connection.delete_table(table_name) # [END deleting_a_table] + finally: connection.close() if __name__ == '__main__': parser = argparse.ArgumentParser( - description='A sample application that connects to Cloud' + - ' Bigtable.', + description=__doc__, formatter_class=argparse.ArgumentDefaultsHelpFormatter) - parser.add_argument( - 'project_id', - help='Google Cloud Platform project ID that contains the Cloud' + - ' Bigtable cluster.') + parser.add_argument('project_id', help='Your Cloud Platform project ID.') parser.add_argument( 'cluster', help='ID of the Cloud Bigtable cluster to connect to.') parser.add_argument( diff --git a/bigtable/hello_happybase/requirements.txt b/bigtable/hello_happybase/requirements.txt index 93130c94378..5cb34f73a1c 100644 --- a/bigtable/hello_happybase/requirements.txt +++ b/bigtable/hello_happybase/requirements.txt @@ -1 +1 @@ -gcloud[grpc]==0.14.0 +gcloud[grpc]==0.16.0