From a6de73e8d96877678bed63e8e111c805c3c0abf5 Mon Sep 17 00:00:00 2001 From: Carlos O'Ryan Date: Tue, 9 Feb 2021 20:26:21 +0000 Subject: [PATCH 1/2] feat: implement Cloud Bigtable tutorial code --- ci/README.md | 57 ++++++++++++- examples/CMakeLists.txt | 13 +-- .../tutorial_cloud_bigtable/CMakeLists.txt | 23 +++++ .../tutorial_cloud_bigtable.cc | 84 +++++++++++++++++++ .../site/tutorial_cloud_bigtable/vcpkg.json | 9 ++ 5 files changed, 180 insertions(+), 6 deletions(-) create mode 100644 examples/site/tutorial_cloud_bigtable/CMakeLists.txt create mode 100644 examples/site/tutorial_cloud_bigtable/tutorial_cloud_bigtable.cc create mode 100644 examples/site/tutorial_cloud_bigtable/vcpkg.json diff --git a/ci/README.md b/ci/README.md index 9ae1206c..d1b5d836 100644 --- a/ci/README.md +++ b/ci/README.md @@ -252,7 +252,7 @@ gcloud logging read \ "resource.type=cloud_run_revision AND resource.labels.service_name=gcf-hello-world-storage AND logName:stdout" ``` -## Run the Cloud Build +## Run the Cloud Build script Finally verify this works by running the Cloud Build: @@ -262,3 +262,58 @@ gcloud builds submit \ "--substitutions=SHORT_SHA=$(git rev-parse --short HEAD)" \ "--config=ci/build-examples.yaml" ``` + +## Testing the Tutorials + +There are a small number of code examples used in more advanced tutorials, +showing how to use functions with other services, e.g. Bigtable or Spanner. + +### Bigtable + +Create a bigtable instance: + +```shell +cbt -project "${GOOGLE_CLOUD_PROJECT}" createinstance \ + test-instance-0 "Test Instance for CI Builds" test-cluster-0 us-central1-f 1 HDD +``` + +Create a bigtable table: + +```shell +cbt -project "${GOOGLE_CLOUD_PROJECT}" -instance test-instance-0 \ + createtable test-table families=stats_summary +``` + +Populate some data in the table: + +```shell +cbt -project "${GOOGLE_CLOUD_PROJECT}" -instance test-instance-0 \ + set test-table "phone#555-1234#20210210" \ + "stats_summary:os_build=PQ2A.190405.003" "stats_summary:os_name=android" +cbt -project "${GOOGLE_CLOUD_PROJECT}" -instance test-instance-0 \ + set test-table "phone#555-2345#20210210" \ + "stats_summary:os_build=PQ2A.190405.003" "stats_summary:os_name=android" +``` + +Build & deploy the Bigtable tutorial function: + +```shell +pack build -v \ + --env TARGET_FUNCTION=tutorial_cloud_bigtable \ + --path examples/site/tutorial_cloud_bigtable \ + "gcr.io/${GOOGLE_CLOUD_PROJECT}/gcf-tutorial-cloud-bigtable" +docker push "gcr.io/${GOOGLE_CLOUD_PROJECT}/gcf-tutorial-cloud-bigtable" +gcloud run deploy gcf-tutorial-cloud-bigtable \ + --project="${GOOGLE_CLOUD_PROJECT}" \ + --image="gcr.io/${GOOGLE_CLOUD_PROJECT}/gcf-tutorial-cloud-bigtable:latest" \ + --region="us-central1" \ + --platform="managed" \ + --allow-unauthenticated +BIGTABLE_SERVICE_URL=$(gcloud run services describe \ + --project="${GOOGLE_CLOUD_PROJECT}" \ + --platform="managed" \ + --region="us-central1" \ + --format="value(status.url)" \ + gcf-tutorial-cloud-bigtable) +curl -H "projectID: ${GOOGLE_CLOUD_PROJECT}" -H "instanceID: test-instance-0" -H "tableID: test-table" "${BIGTABLE_SERVICE_URL}" +``` \ No newline at end of file diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 0e581241..2a6cf645 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -14,10 +14,11 @@ # limitations under the License. # ~~~ -find_package(google_cloud_cpp_storage REQUIRED) -find_package(google_cloud_cpp_pubsub REQUIRED) -find_package(fmt REQUIRED) find_package(Boost REQUIRED COMPONENTS log) +find_package(fmt REQUIRED) +find_package(google_cloud_cpp_bigtable REQUIRED) +find_package(google_cloud_cpp_pubsub REQUIRED) +find_package(google_cloud_cpp_storage REQUIRED) add_library( functions_framework_examples # cmake-format: sort @@ -49,7 +50,8 @@ add_library( site/tips_infinite_retries/tips_infinite_retries.cc site/tips_lazy_globals/tips_lazy_globals.cc site/tips_retry/tips_retry.cc - site/tips_scopes/tips_scopes.cc) + site/tips_scopes/tips_scopes.cc + site/tutorial_cloud_bigtable/tutorial_cloud_bigtable.cc) functions_framework_cpp_add_common_options(functions_framework_examples) if (MSVC) set_property( @@ -59,7 +61,8 @@ if (MSVC) endif () target_link_libraries( functions_framework_examples fmt::fmt functions-framework-cpp::framework - google-cloud-cpp::pubsub google-cloud-cpp::storage) + google-cloud-cpp::bigtable google-cloud-cpp::pubsub + google-cloud-cpp::storage) if (BUILD_TESTING) find_package(GTest CONFIG REQUIRED) diff --git a/examples/site/tutorial_cloud_bigtable/CMakeLists.txt b/examples/site/tutorial_cloud_bigtable/CMakeLists.txt new file mode 100644 index 00000000..c0b3cc5c --- /dev/null +++ b/examples/site/tutorial_cloud_bigtable/CMakeLists.txt @@ -0,0 +1,23 @@ +# ~~~ +# Copyright 2020 Google LLC +# +# 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. +# ~~~ + +find_package(google_cloud_cpp_bigtable REQUIRED) +find_package(functions_framework_cpp REQUIRED) + +add_library(functions_framework_cpp_function tutorial_cloud_bigtable.cc) +target_link_libraries( + functions_framework_cpp_function functions-framework-cpp::framework + google-cloud-cpp::bigtable) diff --git a/examples/site/tutorial_cloud_bigtable/tutorial_cloud_bigtable.cc b/examples/site/tutorial_cloud_bigtable/tutorial_cloud_bigtable.cc new file mode 100644 index 00000000..f4212406 --- /dev/null +++ b/examples/site/tutorial_cloud_bigtable/tutorial_cloud_bigtable.cc @@ -0,0 +1,84 @@ +// Copyright 2021 Google LLC +// +// 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. + +// [START bigtable_functions_quickstart] +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace gcf = ::google::cloud::functions; +namespace cbt = ::google::cloud::bigtable; + +cbt::Table get_table_client(std::string project_id, std::string instance_id, + std::string const& table_id) { + static std::mutex mu; + static std::unique_ptr table; + std::lock_guard lk(mu); + if (table == nullptr || table->table_id() != table_id || + table->instance_id() != instance_id || + table->project_id() != project_id) { + table = std::make_unique( + cbt::CreateDefaultDataClient(std::move(project_id), + std::move(instance_id), + cbt::ClientOptions{}), + table_id); + } + return *table; +} + +gcf::HttpResponse tutorial_cloud_bigtable(gcf::HttpRequest request) { // NOLINT + auto get_header = [h = request.headers()](std::string key) { + std::transform(key.begin(), key.end(), key.begin(), + [](auto x) { return static_cast(std::tolower(x)); }); + auto l = h.find(key); + if (l == h.end()) throw std::invalid_argument("Missing header: " + key); + return l->second; + }; + + auto project_id = get_header("projectID"); + auto instance_id = get_header("instanceID"); + auto table_id = get_header("tableID"); + auto table = + get_table_client(std::move(project_id), std::move(instance_id), table_id); + + std::ostringstream os; + auto filter = + cbt::Filter::Chain(cbt::Filter::Latest(1), + cbt::Filter::ColumnName("stats_summary", "os_build")); + for (auto row : table.ReadRows(cbt::RowRange::Prefix("phone#"), filter)) { + if (!row) { + std::ostringstream err; + err << "Error reading from bigtable: " << row.status(); + throw std::runtime_error(std::move(err).str()); + } + for (auto const& cell : row->cells()) { + os << "Rowkey: " << cell.row_key() << ", os_build: " << cell.value() + << "\n"; + } + } + + gcf::HttpResponse response; + response.set_payload(std::move(os).str()); + response.set_header("content-type", "text/plain"); + return response; +} +// [END bigtable_functions_quickstart] diff --git a/examples/site/tutorial_cloud_bigtable/vcpkg.json b/examples/site/tutorial_cloud_bigtable/vcpkg.json new file mode 100644 index 00000000..23631759 --- /dev/null +++ b/examples/site/tutorial_cloud_bigtable/vcpkg.json @@ -0,0 +1,9 @@ +{ + "name": "tutorial-cloud-bigtable", + "version-string": "unversioned", + "dependencies": [ + "fmt", + "functions-framework-cpp", + "google-cloud-cpp" + ] +} From e2fcaa326ee4e929ba3e5ff036db345e2b82aa26 Mon Sep 17 00:00:00 2001 From: Carlos O'Ryan Date: Wed, 10 Feb 2021 04:01:58 +0000 Subject: [PATCH 2/2] Address review comments --- examples/site/tutorial_cloud_bigtable/CMakeLists.txt | 2 +- .../site/tutorial_cloud_bigtable/tutorial_cloud_bigtable.cc | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/examples/site/tutorial_cloud_bigtable/CMakeLists.txt b/examples/site/tutorial_cloud_bigtable/CMakeLists.txt index c0b3cc5c..99a81a3a 100644 --- a/examples/site/tutorial_cloud_bigtable/CMakeLists.txt +++ b/examples/site/tutorial_cloud_bigtable/CMakeLists.txt @@ -1,5 +1,5 @@ # ~~~ -# Copyright 2020 Google LLC +# Copyright 2021 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/examples/site/tutorial_cloud_bigtable/tutorial_cloud_bigtable.cc b/examples/site/tutorial_cloud_bigtable/tutorial_cloud_bigtable.cc index f4212406..c789b2bf 100644 --- a/examples/site/tutorial_cloud_bigtable/tutorial_cloud_bigtable.cc +++ b/examples/site/tutorial_cloud_bigtable/tutorial_cloud_bigtable.cc @@ -18,12 +18,9 @@ #include #include #include -#include #include -#include #include #include -#include namespace gcf = ::google::cloud::functions; namespace cbt = ::google::cloud::bigtable;