From 16e8be84a2280b2a64b4e22b0dd039e3e2180844 Mon Sep 17 00:00:00 2001 From: Scott Hart Date: Tue, 27 Jan 2026 14:54:06 -0500 Subject: [PATCH 1/8] impl(v3): remove deprecated Bigtable Admin classes --- doc/v3-migration-guide.md | 114 ++ google/cloud/bigtable/CMakeLists.txt | 12 - google/cloud/bigtable/admin_client.cc | 34 - google/cloud/bigtable/admin_client.h | 73 -- google/cloud/bigtable/admin_client_test.cc | 34 - .../bigtable/bigtable_client_unit_tests.bzl | 4 - .../run_integration_tests_emulator_bazel.sh | 4 +- .../bigtable/examples/table_admin_snippets.cc | 27 +- .../bigtable/google_cloud_cpp_bigtable.bzl | 8 - google/cloud/bigtable/instance_admin.cc | 232 ---- google/cloud/bigtable/instance_admin.h | 732 ----------- .../cloud/bigtable/instance_admin_client.cc | 33 - google/cloud/bigtable/instance_admin_client.h | 69 - .../bigtable/instance_admin_client_test.cc | 34 - google/cloud/bigtable/instance_admin_test.cc | 694 ---------- google/cloud/bigtable/table_admin.cc | 349 ----- google/cloud/bigtable/table_admin.h | 1136 ----------------- google/cloud/bigtable/table_admin_test.cc | 950 -------------- .../testing/embedded_server_test_fixture.h | 1 - .../bigtable/testing/table_integration_test.h | 10 + google/cloud/bigtable/tests/CMakeLists.txt | 9 +- .../bigtable_client_integration_tests.bzl | 6 +- .../tests/instance_admin_integration_test.cc | 278 ++-- ...=> table_admin_backup_integration_test.cc} | 93 +- ...able_admin_iam_policy_integration_test.cc} | 28 +- ...est.cc => table_admin_integration_test.cc} | 234 ++-- google/cloud/bigtable/wait_for_consistency.cc | 33 +- google/cloud/bigtable/wait_for_consistency.h | 33 + 28 files changed, 597 insertions(+), 4667 deletions(-) delete mode 100644 google/cloud/bigtable/admin_client.cc delete mode 100644 google/cloud/bigtable/admin_client.h delete mode 100644 google/cloud/bigtable/admin_client_test.cc delete mode 100644 google/cloud/bigtable/instance_admin.cc delete mode 100644 google/cloud/bigtable/instance_admin.h delete mode 100644 google/cloud/bigtable/instance_admin_client.cc delete mode 100644 google/cloud/bigtable/instance_admin_client.h delete mode 100644 google/cloud/bigtable/instance_admin_client_test.cc delete mode 100644 google/cloud/bigtable/instance_admin_test.cc delete mode 100644 google/cloud/bigtable/table_admin.cc delete mode 100644 google/cloud/bigtable/table_admin.h delete mode 100644 google/cloud/bigtable/table_admin_test.cc rename google/cloud/bigtable/tests/{admin_backup_integration_test.cc => table_admin_backup_integration_test.cc} (55%) rename google/cloud/bigtable/tests/{admin_iam_policy_integration_test.cc => table_admin_iam_policy_integration_test.cc} (76%) rename google/cloud/bigtable/tests/{admin_integration_test.cc => table_admin_integration_test.cc} (60%) diff --git a/doc/v3-migration-guide.md b/doc/v3-migration-guide.md index b2ea23f60a432..f6de9f20fb103 100644 --- a/doc/v3-migration-guide.md +++ b/doc/v3-migration-guide.md @@ -487,6 +487,120 @@ internal legacy files. +
+Removed bigtable::AdminClient and bigtable::TableAdmin + +The `bigtable::AdminClient` class and `bigtable::TableAdmin` class have been +replaced with `bigtable_admin::BigtableTableAdminClient`. + +**Before:** + +```cpp + +std::shared_ptr admin_client = + bigtable::MakeAdminClient("project-id"); +auto table_admin = std::make_unique( + admin_client, "instance-id"); + +// Drop a selection of rows by key prefix. +auto result = table_admin.DropRowByPrefix("table-id", "row-key-prefix"); + +// Drop all rows. +result = table_admin.DropAllRows("table-id"); +``` + +**After:** + +```cpp +#include "google/cloud/bigtable/admin/bigtable_table_admin_client.h" + +auto table_admin = bigtable_admin::BigtableTableAdminClient( + bigtable_admin::MakeBigtableAdminConnection()); +auto table_name = bigtable::TableName("project-id", "instance-id", "table-id"); + +// Drop a selection of rows by key prefix. +google::bigtable::admin::v2::DropRowRangeRequest drop_rows_by_prefix; +drop_rows_by_prefix.set_name(table_name); +drop_rows_by_prefix.set_row_key_prefix("row-key-prefix"); +auto result = table_admin.DropRowRange(drop_rows_by_prefix); + +// Drop all rows. +google::bigtable::admin::v2::DropRowRangeRequest drop_all_rows; +drop_all_rows.set_name(table_name); +drop_all_rows.set_delete_all_data_from_table(true); +result = table_admin.DropRowRange(drop_all_rows); +``` + +
+ +
WaitForConsistency is now a free function + +With the removal of the `bigtable::TableAdmin` class, `WaitForConsistency` is +now a free function. + +**Before:** + +```cpp + +std::shared_ptr admin_client = + bigtable::MakeAdminClient("project-id"); +auto table_admin = std::make_unique( + admin_client, "instance-id"); + +auto token = table_admin.GenerateConsistencyToken("table-id"); +if (!token) throw std::runtime_error(token.status().message()); +auto result = table_admin.WaitForConsistency("table-id", *token); +``` + +**After:** + +```cpp +#include "google/cloud/bigtable/admin/bigtable_table_admin_client.h" +#include "google/cloud/bigtable/wait_for_consistency.h" + +auto connection = bigtable_admin::MakeBigtableAdminConnection(); +auto table_admin = bigtable_admin::BigtableTableAdminClient(connection); +auto table_name = bigtable::TableName("project-id", "instance-id", "table-id"); + +auto token = table_admin.GenerateConsistencyToken(table_name); +if (!token) throw std::runtime_error(token.status().message()); +auto result = bigtable_admin::WaitForConsistency(connection, table_name, + token->consistency_token()); +``` + +
+ +
+Removed bigtable::InstanceAdminClient and bigtable::InstanceAdmin + +The `bigtable::InstanceAdminClient` class and `bigtable::InstanceAdmin` class +have been replaced with `bigtable_admin::BigtableInstanceAdminClient`. + +**Before:** + +```cpp +auto instance_admin_client = bigtable::MakeInstanceAdminClient("project-id"); +auto instance_admin = + std::make_unique(instance_admin_client); + +auto clusters = instance_admin->ListClusters(); +``` + +**After:** + +```cpp +#include "google/cloud/bigtable/admin/bigtable_instance_admin_client.h" + +auto instance_admin = + std::make_unique( + bigtable_admin::MakeBigtableInstanceAdminConnection()); + +auto clusters = instance_admin->ListClusters( + InstanceName("project-id", "instance-id")); +``` + +
+ ### Pubsub
diff --git a/google/cloud/bigtable/CMakeLists.txt b/google/cloud/bigtable/CMakeLists.txt index 167b66bd2cb09..eb224a2e00832 100644 --- a/google/cloud/bigtable/CMakeLists.txt +++ b/google/cloud/bigtable/CMakeLists.txt @@ -104,8 +104,6 @@ add_library( admin/internal/bigtable_table_admin_tracing_connection.h admin/internal/bigtable_table_admin_tracing_stub.cc admin/internal/bigtable_table_admin_tracing_stub.h - admin_client.cc - admin_client.h app_profile_config.cc app_profile_config.h bound_query.cc @@ -131,10 +129,6 @@ add_library( iam_policy.h idempotent_mutation_policy.cc idempotent_mutation_policy.h - instance_admin.cc - instance_admin.h - instance_admin_client.cc - instance_admin_client.h instance_config.cc instance_config.h instance_list_responses.h @@ -259,8 +253,6 @@ add_library( sql_statement.h table.cc table.h - table_admin.cc - table_admin.h table_config.cc table_config.h table_resource.cc @@ -424,7 +416,6 @@ if (BUILD_TESTING) # List the unit tests, then setup the targets and dependencies. set(bigtable_client_unit_tests # cmake-format: sort - admin_client_test.cc app_profile_config_test.cc async_read_stream_test.cc bigtable_version_test.cc @@ -441,8 +432,6 @@ if (BUILD_TESTING) iam_binding_test.cc iam_policy_test.cc idempotent_mutation_policy_test.cc - instance_admin_client_test.cc - instance_admin_test.cc instance_config_test.cc instance_resource_test.cc instance_update_config_test.cc @@ -490,7 +479,6 @@ if (BUILD_TESTING) rpc_backoff_policy_test.cc rpc_retry_policy_test.cc sql_statement_test.cc - table_admin_test.cc table_config_test.cc table_resource_test.cc table_test.cc diff --git a/google/cloud/bigtable/admin_client.cc b/google/cloud/bigtable/admin_client.cc deleted file mode 100644 index 4bcf80c036e36..0000000000000 --- a/google/cloud/bigtable/admin_client.cc +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2017 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 -// -// https://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. - -#include "google/cloud/bigtable/admin_client.h" -#include "google/cloud/bigtable/internal/defaults.h" - -namespace google { -namespace cloud { -namespace bigtable { -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN - -std::shared_ptr MakeAdminClient(std::string project, - Options options) { - auto params = bigtable_internal::AdminClientParams( - internal::DefaultTableAdminOptions(std::move(options))); - return std::shared_ptr( - new AdminClient(std::move(project), std::move(params))); -} - -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END -} // namespace bigtable -} // namespace cloud -} // namespace google diff --git a/google/cloud/bigtable/admin_client.h b/google/cloud/bigtable/admin_client.h deleted file mode 100644 index 9f8dd1b5b9aab..0000000000000 --- a/google/cloud/bigtable/admin_client.h +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2017 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 -// -// https://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. - -#ifndef GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_ADMIN_CLIENT_H -#define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_ADMIN_CLIENT_H - -#include "google/cloud/bigtable/admin/bigtable_table_admin_connection.h" -#include "google/cloud/bigtable/internal/admin_client_params.h" -#include "google/cloud/bigtable/version.h" -#include "google/cloud/grpc_options.h" -#include "google/cloud/options.h" -#include -#include - -namespace google { -namespace cloud { -namespace bigtable { -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN - -/** - * Creates a `bigtable_admin::BigtableTableAdminConnection` and a - * `CompletionQueue` for `bigtable::TableAdmin` to use. - * - * This class is used to initiate a connection to the Cloud Bigtable Table - * Admin service. It is maintained only for backwards compatibility. - * - * @note Please prefer using `bigtable_admin::BigtableTableAdminConnection` to - * configure `bigtable_admin::BigtableTableAdminClient`, instead of using - * this class to configure `bigtable::TableAdmin`. - */ -class AdminClient final { - public: - /// The project id that this AdminClient works on. - std::string const& project() { return project_; }; - - private: - friend class TableAdmin; - friend std::shared_ptr MakeAdminClient(std::string, Options); - - AdminClient(std::string project, bigtable_internal::AdminClientParams params) - : project_(std::move(project)), - cq_(params.options.get()), - background_threads_(std::move(params.background_threads)), - connection_(bigtable_admin::MakeBigtableTableAdminConnection( - std::move(params.options))) {} - - std::string project_; - CompletionQueue cq_; - std::shared_ptr background_threads_; - std::shared_ptr connection_; -}; - -/// Create a new table admin client configured via @p options. -std::shared_ptr MakeAdminClient(std::string project, - Options options = {}); - -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END -} // namespace bigtable -} // namespace cloud -} // namespace google - -#endif // GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_ADMIN_CLIENT_H diff --git a/google/cloud/bigtable/admin_client_test.cc b/google/cloud/bigtable/admin_client_test.cc deleted file mode 100644 index d723f8a64ff1b..0000000000000 --- a/google/cloud/bigtable/admin_client_test.cc +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2017 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 -// -// https://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. - -#include "google/cloud/bigtable/admin_client.h" -#include - -namespace google { -namespace cloud { -namespace bigtable { -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN -namespace { - -TEST(AdminClientTest, MakeClient) { - auto admin_client = MakeAdminClient("test-project"); - ASSERT_TRUE(admin_client); - EXPECT_EQ("test-project", admin_client->project()); -} - -} // namespace -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END -} // namespace bigtable -} // namespace cloud -} // namespace google diff --git a/google/cloud/bigtable/bigtable_client_unit_tests.bzl b/google/cloud/bigtable/bigtable_client_unit_tests.bzl index 471fcefdadcd3..3a5760e1ae6e3 100644 --- a/google/cloud/bigtable/bigtable_client_unit_tests.bzl +++ b/google/cloud/bigtable/bigtable_client_unit_tests.bzl @@ -17,7 +17,6 @@ """Automatically generated unit tests list - DO NOT EDIT.""" bigtable_client_unit_tests = [ - "admin_client_test.cc", "app_profile_config_test.cc", "async_read_stream_test.cc", "bigtable_version_test.cc", @@ -34,8 +33,6 @@ bigtable_client_unit_tests = [ "iam_binding_test.cc", "iam_policy_test.cc", "idempotent_mutation_policy_test.cc", - "instance_admin_client_test.cc", - "instance_admin_test.cc", "instance_config_test.cc", "instance_resource_test.cc", "instance_update_config_test.cc", @@ -83,7 +80,6 @@ bigtable_client_unit_tests = [ "rpc_backoff_policy_test.cc", "rpc_retry_policy_test.cc", "sql_statement_test.cc", - "table_admin_test.cc", "table_config_test.cc", "table_resource_test.cc", "table_test.cc", diff --git a/google/cloud/bigtable/ci/run_integration_tests_emulator_bazel.sh b/google/cloud/bigtable/ci/run_integration_tests_emulator_bazel.sh index 966435e0bb52e..ba218743f7e64 100755 --- a/google/cloud/bigtable/ci/run_integration_tests_emulator_bazel.sh +++ b/google/cloud/bigtable/ci/run_integration_tests_emulator_bazel.sh @@ -59,8 +59,8 @@ source module /google/cloud/bigtable/tools/run_emulator_utils.sh production_only_targets=( "//google/cloud/bigtable/examples:bigtable_table_admin_backup_snippets" "//google/cloud/bigtable/examples:table_admin_iam_policy_snippets" - "//google/cloud/bigtable/tests:admin_backup_integration_test" - "//google/cloud/bigtable/tests:admin_iam_policy_integration_test" + "//google/cloud/bigtable/tests:table_admin_backup_integration_test" + "//google/cloud/bigtable/tests:table_admin_iam_policy_integration_test" ) # Coverage builds are more subject to flakiness, as we must explicitly disable diff --git a/google/cloud/bigtable/examples/table_admin_snippets.cc b/google/cloud/bigtable/examples/table_admin_snippets.cc index e3d2ae8b08a14..18d206f55cab1 100644 --- a/google/cloud/bigtable/examples/table_admin_snippets.cc +++ b/google/cloud/bigtable/examples/table_admin_snippets.cc @@ -14,7 +14,6 @@ #include "google/cloud/bigtable/admin/bigtable_table_admin_client.h" #include "google/cloud/bigtable/examples/bigtable_examples_common.h" -#include "google/cloud/bigtable/table_admin.h" #include "google/cloud/bigtable/testing/cleanup_stale_resources.h" #include "google/cloud/bigtable/testing/random_names.h" #include "google/cloud/bigtable/wait_for_consistency.h" @@ -633,30 +632,22 @@ void WaitForConsistencyCheck( using ::google::cloud::future; using ::google::cloud::Status; using ::google::cloud::StatusOr; - [](cbta::BigtableTableAdminClient admin, std::string const& project_id, + [](cbta::BigtableTableAdminClient, std::string const& project_id, std::string const& instance_id, std::string const& table_id) { + auto connection = cbta::MakeBigtableTableAdminConnection(); + auto client = cbta::BigtableTableAdminClient(connection); std::string table_name = cbt::TableName(project_id, instance_id, table_id); StatusOr - consistency_token = admin.GenerateConsistencyToken(table_name); + consistency_token = client.GenerateConsistencyToken(table_name); if (!consistency_token) { throw std::move(consistency_token).status(); } - // Start a thread to perform the background work. - CompletionQueue cq; - std::thread cq_runner([&cq] { cq.Run(); }); - - std::string token = consistency_token->consistency_token(); - future consistent_future = - cbta::AsyncWaitForConsistency(cq, admin, table_name, token); - - // Simplify the example by blocking until the operation is done. - Status status = consistent_future.get(); - if (!status.ok()) throw std::runtime_error(status.message()); + auto token = consistency_token->consistency_token(); + auto consistency_future = + cbta::WaitForConsistency(connection, table_name, token); + StatusOr consistency = consistency_future.get(); + if (!consistency) throw std::runtime_error(consistency.status().message()); std::cout << "Table is consistent with token " << token << "\n"; - - // Shutdown the work queue and join the background thread - cq.Shutdown(); - cq_runner.join(); } //! [wait for consistency check] (std::move(admin), argv.at(0), argv.at(1), argv.at(2)); diff --git a/google/cloud/bigtable/google_cloud_cpp_bigtable.bzl b/google/cloud/bigtable/google_cloud_cpp_bigtable.bzl index ab40205c5efe5..3ff61adedaea1 100644 --- a/google/cloud/bigtable/google_cloud_cpp_bigtable.bzl +++ b/google/cloud/bigtable/google_cloud_cpp_bigtable.bzl @@ -45,7 +45,6 @@ google_cloud_cpp_bigtable_hdrs = [ "admin/internal/bigtable_table_admin_stub_factory.h", "admin/internal/bigtable_table_admin_tracing_connection.h", "admin/internal/bigtable_table_admin_tracing_stub.h", - "admin_client.h", "app_profile_config.h", "bound_query.h", "bytes.h", @@ -61,8 +60,6 @@ google_cloud_cpp_bigtable_hdrs = [ "iam_binding.h", "iam_policy.h", "idempotent_mutation_policy.h", - "instance_admin.h", - "instance_admin_client.h", "instance_config.h", "instance_list_responses.h", "instance_resource.h", @@ -135,7 +132,6 @@ google_cloud_cpp_bigtable_hdrs = [ "rpc_retry_policy.h", "sql_statement.h", "table.h", - "table_admin.h", "table_config.h", "table_resource.h", "timestamp.h", @@ -170,7 +166,6 @@ google_cloud_cpp_bigtable_srcs = [ "admin/internal/bigtable_table_admin_stub_factory.cc", "admin/internal/bigtable_table_admin_tracing_connection.cc", "admin/internal/bigtable_table_admin_tracing_stub.cc", - "admin_client.cc", "app_profile_config.cc", "bound_query.cc", "bytes.cc", @@ -181,8 +176,6 @@ google_cloud_cpp_bigtable_srcs = [ "iam_binding.cc", "iam_policy.cc", "idempotent_mutation_policy.cc", - "instance_admin.cc", - "instance_admin_client.cc", "instance_config.cc", "instance_resource.cc", "instance_update_config.cc", @@ -235,7 +228,6 @@ google_cloud_cpp_bigtable_srcs = [ "rpc_retry_policy.cc", "sql_statement.cc", "table.cc", - "table_admin.cc", "table_config.cc", "table_resource.cc", "timestamp.cc", diff --git a/google/cloud/bigtable/instance_admin.cc b/google/cloud/bigtable/instance_admin.cc deleted file mode 100644 index b5a283c6355e2..0000000000000 --- a/google/cloud/bigtable/instance_admin.cc +++ /dev/null @@ -1,232 +0,0 @@ -// Copyright 2018 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 -// -// https://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. - -#include "google/cloud/bigtable/instance_admin.h" -#include "google/cloud/location.h" -#include -#include -#include - -namespace btadmin = ::google::bigtable::admin::v2; - -namespace google { -namespace cloud { -namespace bigtable { -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN - -static_assert(std::is_copy_assignable::value, - "bigtable::InstanceAdmin must be CopyAssignable"); - -StatusOr InstanceAdmin::ListInstances() { - google::cloud::internal::OptionsSpan span(options_); - InstanceList result; - - // Build the RPC request, try to minimize copying. - btadmin::ListInstancesRequest request; - request.set_parent(project_name()); - auto sor = connection_->ListInstances(request); - if (!sor) return std::move(sor).status(); - auto response = *std::move(sor); - auto& instances = *response.mutable_instances(); - std::move(instances.begin(), instances.end(), - std::back_inserter(result.instances)); - auto& failed_locations = *response.mutable_failed_locations(); - std::move(failed_locations.begin(), failed_locations.end(), - std::back_inserter(result.failed_locations)); - return result; -} - -future> InstanceAdmin::CreateInstance( - InstanceConfig instance_config) { - google::cloud::internal::OptionsSpan span(options_); - auto request = std::move(instance_config).as_proto(); - request.set_parent(project_name()); - for (auto& kv : *request.mutable_clusters()) { - kv.second.set_location( - Location(project_id(), kv.second.location()).FullName()); - } - return connection_->CreateInstance(request); -} - -future> InstanceAdmin::CreateCluster( - ClusterConfig cluster_config, std::string const& instance_id, - std::string const& cluster_id) { - google::cloud::internal::OptionsSpan span(options_); - auto cluster = std::move(cluster_config).as_proto(); - cluster.set_location(Location(project_id(), cluster.location()).FullName()); - btadmin::CreateClusterRequest request; - request.mutable_cluster()->Swap(&cluster); - request.set_parent(InstanceName(instance_id)); - request.set_cluster_id(cluster_id); - return connection_->CreateCluster(request); -} - -future> -InstanceAdmin::UpdateInstance(InstanceUpdateConfig instance_update_config) { - google::cloud::internal::OptionsSpan span(options_); - auto request = std::move(instance_update_config).as_proto(); - return connection_->PartialUpdateInstance(request); -} - -StatusOr InstanceAdmin::GetInstance( - std::string const& instance_id) { - google::cloud::internal::OptionsSpan span(options_); - btadmin::GetInstanceRequest request; - request.set_name(InstanceName(instance_id)); - return connection_->GetInstance(request); -} - -Status InstanceAdmin::DeleteInstance(std::string const& instance_id) { - google::cloud::internal::OptionsSpan span(options_); - btadmin::DeleteInstanceRequest request; - request.set_name(InstanceName(instance_id)); - return connection_->DeleteInstance(request); -} - -StatusOr InstanceAdmin::GetCluster( - std::string const& instance_id, std::string const& cluster_id) { - google::cloud::internal::OptionsSpan span(options_); - btadmin::GetClusterRequest request; - request.set_name(ClusterName(instance_id, cluster_id)); - return connection_->GetCluster(request); -} - -StatusOr InstanceAdmin::ListClusters() { - return ListClusters("-"); -} - -StatusOr InstanceAdmin::ListClusters( - std::string const& instance_id) { - google::cloud::internal::OptionsSpan span(options_); - ClusterList result; - - btadmin::ListClustersRequest request; - request.set_parent(InstanceName(instance_id)); - auto sor = connection_->ListClusters(request); - if (!sor) return std::move(sor).status(); - auto response = *std::move(sor); - auto& clusters = *response.mutable_clusters(); - std::move(clusters.begin(), clusters.end(), - std::back_inserter(result.clusters)); - auto& failed_locations = *response.mutable_failed_locations(); - std::move(failed_locations.begin(), failed_locations.end(), - std::back_inserter(result.failed_locations)); - return result; -} - -future> -InstanceAdmin::UpdateCluster(ClusterConfig cluster_config) { - google::cloud::internal::OptionsSpan span(options_); - auto request = std::move(cluster_config).as_proto(); - return connection_->UpdateCluster(request); -} - -Status InstanceAdmin::DeleteCluster(std::string const& instance_id, - std::string const& cluster_id) { - google::cloud::internal::OptionsSpan span(options_); - btadmin::DeleteClusterRequest request; - request.set_name(ClusterName(instance_id, cluster_id)); - return connection_->DeleteCluster(request); -} - -StatusOr InstanceAdmin::CreateAppProfile( - std::string const& instance_id, AppProfileConfig config) { - google::cloud::internal::OptionsSpan span(options_); - auto request = std::move(config).as_proto(); - request.set_parent(InstanceName(instance_id)); - return connection_->CreateAppProfile(request); -} - -StatusOr InstanceAdmin::GetAppProfile( - std::string const& instance_id, std::string const& profile_id) { - google::cloud::internal::OptionsSpan span(options_); - btadmin::GetAppProfileRequest request; - request.set_name(AppProfileName(instance_id, profile_id)); - return connection_->GetAppProfile(request); -} - -future> InstanceAdmin::UpdateAppProfile( - std::string const& instance_id, std::string const& profile_id, - AppProfileUpdateConfig config) { - google::cloud::internal::OptionsSpan span(options_); - auto request = std::move(config).as_proto(); - request.mutable_app_profile()->set_name( - AppProfileName(instance_id, profile_id)); - return connection_->UpdateAppProfile(request); -} - -StatusOr> InstanceAdmin::ListAppProfiles( - std::string const& instance_id) { - google::cloud::internal::OptionsSpan span(options_); - std::vector result; - - btadmin::ListAppProfilesRequest request; - request.set_parent(InstanceName(instance_id)); - auto sr = connection_->ListAppProfiles(request); - for (auto& ap : sr) { - if (!ap) return std::move(ap).status(); - result.emplace_back(*std::move(ap)); - } - return result; -} - -Status InstanceAdmin::DeleteAppProfile(std::string const& instance_id, - std::string const& profile_id, - bool ignore_warnings) { - google::cloud::internal::OptionsSpan span(options_); - btadmin::DeleteAppProfileRequest request; - request.set_name(AppProfileName(instance_id, profile_id)); - request.set_ignore_warnings(ignore_warnings); - return connection_->DeleteAppProfile(request); -} - -StatusOr InstanceAdmin::GetNativeIamPolicy( - std::string const& instance_id) { - google::cloud::internal::OptionsSpan span(options_); - google::iam::v1::GetIamPolicyRequest request; - request.set_resource(InstanceName(instance_id)); - return connection_->GetIamPolicy(request); -} - -StatusOr InstanceAdmin::SetIamPolicy( - std::string const& instance_id, google::iam::v1::Policy const& iam_policy) { - google::cloud::internal::OptionsSpan span(options_); - google::iam::v1::SetIamPolicyRequest request; - request.set_resource(InstanceName(instance_id)); - *request.mutable_policy() = iam_policy; - return connection_->SetIamPolicy(request); -} - -StatusOr> InstanceAdmin::TestIamPermissions( - std::string const& instance_id, - std::vector const& permissions) { - google::cloud::internal::OptionsSpan span(options_); - google::iam::v1::TestIamPermissionsRequest request; - request.set_resource(InstanceName(instance_id)); - for (auto const& permission : permissions) { - request.add_permissions(permission); - } - auto sor = connection_->TestIamPermissions(request); - if (!sor) return std::move(sor).status(); - auto response = *std::move(sor); - std::vector result; - auto& ps = *response.mutable_permissions(); - std::move(ps.begin(), ps.end(), std::back_inserter(result)); - return result; -} - -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END -} // namespace bigtable -} // namespace cloud -} // namespace google diff --git a/google/cloud/bigtable/instance_admin.h b/google/cloud/bigtable/instance_admin.h deleted file mode 100644 index e7f218261fd07..0000000000000 --- a/google/cloud/bigtable/instance_admin.h +++ /dev/null @@ -1,732 +0,0 @@ -// Copyright 2018 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 -// -// https://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. - -#ifndef GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_INSTANCE_ADMIN_H -#define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_INSTANCE_ADMIN_H - -#include "google/cloud/bigtable/admin/bigtable_instance_admin_connection.h" -#include "google/cloud/bigtable/admin/bigtable_instance_admin_options.h" -#include "google/cloud/bigtable/app_profile_config.h" -#include "google/cloud/bigtable/cluster_config.h" -#include "google/cloud/bigtable/cluster_list_responses.h" -#include "google/cloud/bigtable/completion_queue.h" -#include "google/cloud/bigtable/iam_policy.h" -#include "google/cloud/bigtable/instance_admin_client.h" -#include "google/cloud/bigtable/instance_config.h" -#include "google/cloud/bigtable/instance_list_responses.h" -#include "google/cloud/bigtable/instance_update_config.h" -#include "google/cloud/bigtable/internal/convert_policies.h" -#include "google/cloud/bigtable/polling_policy.h" -#include "google/cloud/bigtable/resource_names.h" -#include "google/cloud/bigtable/version.h" -#include "google/cloud/future.h" -#include "google/cloud/project.h" -#include "google/cloud/status_or.h" -#include -#include -#include -#include - -namespace google { -namespace cloud { -namespace bigtable_internal { -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN -class InstanceAdminTester; -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END -} // namespace bigtable_internal -namespace bigtable { -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN - -/** - * Implements the APIs to administer Cloud Bigtable instances. - * - * @par Thread-safety - * Instances of this class created via copy-construction or copy-assignment - * share the underlying pool of connections. Access to these copies via multiple - * threads is guaranteed to work. Two threads operating concurrently on the same - * instance of this class is not guaranteed to work. - * - * @par Cost - * Creating a new object of type `InstanceAdmin` is comparable to creating a few - * objects of type `std::string` or a few objects of type - * `std::shared_ptr`. The class represents a shallow handle to a remote - * object. - * - * @par Error Handling - * This class uses `StatusOr` to report errors. When an operation fails to - * perform its work the returned `StatusOr` contains the error details. If - * the `ok()` member function in the `StatusOr` returns `true` then it - * contains the expected result. Operations that do not return a value simply - * return a `google::cloud::Status` indicating success or the details of the - * error Please consult the [`StatusOr` - * documentation](#google::cloud::StatusOr) for more details. - * - * @code - * namespace cbt = google::cloud::bigtable; - * namespace btadmin = google::bigtable::admin::v2; - * cbt::InstanceAdmin admin = ...; - * google::cloud::StatusOr instance = admin.GetInstance(...); - * - * if (!instance) { - * std::cerr << "Error fetching instance\n"; - * return; - * } - * - * // Use `instance` as a smart pointer here, e.g.: - * std::cout << "The full instance name is " << instance->name() << "\n"; - * @endcode - * - * In addition, the @ref index "main page" contains examples using `StatusOr` - * to handle errors. - * - * @par Retry, Backoff, and Idempotency Policies - * The library automatically retries requests that fail with transient errors, - * and uses [truncated exponential backoff][backoff-link] to backoff between - * retries. The default policies are to continue retrying for up to 10 minutes. - * On each transient failure the backoff period is doubled, starting with an - * initial backoff of 100 milliseconds. The backoff period growth is truncated - * at 60 seconds. The default idempotency policy is to only retry idempotent - * operations. Note that most operations that change state are **not** - * idempotent. - * - * The application can override these policies when constructing objects of this - * class. The documentation for the constructors show examples of this in - * action. - * - * [backoff-link]: https://cloud.google.com/storage/docs/exponential-backoff - * - * @see https://cloud.google.com/bigtable/ for an overview of Cloud Bigtable. - * - * @see https://cloud.google.com/bigtable/docs/overview for an overview of the - * Cloud Bigtable data model. - * - * @see https://cloud.google.com/bigtable/docs/instances-clusters-nodes for an - * introduction of the main APIs into Cloud Bigtable. - * - * @see https://cloud.google.com/bigtable/docs/reference/service-apis-overview - * for an overview of the underlying Cloud Bigtable API. - * - * @see #google::cloud::StatusOr for a description of the error reporting class - * used by this library. - * - * @see `LimitedTimeRetryPolicy` and `LimitedErrorCountRetryPolicy` for - * alternative retry policies. - * - * @see `ExponentialBackoffPolicy` to configure different parameters for the - * exponential backoff policy. - * - * @see `SafeIdempotentMutationPolicy` and `AlwaysRetryMutationPolicy` for - * alternative idempotency policies. - */ -class InstanceAdmin { - public: - explicit InstanceAdmin( - std::shared_ptr - connection, - std::string project) - : connection_(std::move(connection)), - project_id_(std::move(project)), - project_name_(Project(project_id_).FullName()), - retry_prototype_( - DefaultRPCRetryPolicy(internal::kBigtableInstanceAdminLimits)), - backoff_prototype_( - DefaultRPCBackoffPolicy(internal::kBigtableInstanceAdminLimits)), - polling_prototype_( - DefaultPollingPolicy(internal::kBigtableInstanceAdminLimits)), - options_(google::cloud::internal::MergeOptions( - bigtable_internal::MakeInstanceAdminOptions( - retry_prototype_, backoff_prototype_, polling_prototype_), - connection_->options())) {} - - /** - * @param client the interface to create grpc stubs, report errors, etc. - */ - // NOLINTNEXTLINE(performance-unnecessary-value-param) - explicit InstanceAdmin(std::shared_ptr client) - : InstanceAdmin(client->connection_, client->project()) {} - - /** - * Create a new InstanceAdmin using explicit policies to handle RPC errors. - * - * @param client the interface to create grpc stubs, report errors, etc. - * @param policies the set of policy overrides for this object. - * @tparam Policies the types of the policies to override, the types must - * derive from one of the following types: - * - `RPCBackoffPolicy` how to backoff from a failed RPC. Currently only - * `ExponentialBackoffPolicy` is implemented. You can also create your - * own policies that backoff using a different algorithm. - * - `RPCRetryPolicy` for how long to retry failed RPCs. Use - * `LimitedErrorCountRetryPolicy` to limit the number of failures - * allowed. Use `LimitedTimeRetryPolicy` to bound the time for any - * request. You can also create your own policies that combine time and - * error counts. - * - `PollingPolicy` for how long will the class wait for - * `google.longrunning.Operation` to complete. This class combines both - * the backoff policy for checking long running operations and the - * retry policy. - * - * @see GenericPollingPolicy, ExponentialBackoffPolicy, - * LimitedErrorCountRetryPolicy, LimitedTimeRetryPolicy. - */ - template - // NOLINTNEXTLINE(performance-unnecessary-value-param) - explicit InstanceAdmin(std::shared_ptr client, - Policies&&... policies) - : connection_(client->connection_), - project_id_(client->project()), - project_name_(Project(project_id_).FullName()), - retry_prototype_( - DefaultRPCRetryPolicy(internal::kBigtableInstanceAdminLimits)), - backoff_prototype_( - DefaultRPCBackoffPolicy(internal::kBigtableInstanceAdminLimits)), - polling_prototype_( - DefaultPollingPolicy(internal::kBigtableInstanceAdminLimits)) { - ChangePolicies(std::forward(policies)...); - options_ = google::cloud::internal::MergeOptions( - bigtable_internal::MakeInstanceAdminOptions( - retry_prototype_, backoff_prototype_, polling_prototype_), - connection_->options()); - } - - /// The full name (`projects/`) of the project. - std::string const& project_name() const { return project_name_; } - /// The project id, i.e., `project_name()` without the `projects/` prefix. - std::string const& project_id() const { return project_id_; } - - /** - * Returns an InstanceAdmin that reuses the connection and configuration of - * this InstanceAdmin, but with a different resource name. - */ - InstanceAdmin WithNewTarget(std::string project_id) const { - auto admin = *this; - admin.project_id_ = std::move(project_id); - admin.project_name_ = Project(admin.project_id_).FullName(); - return admin; - } - - /// Return the fully qualified name of the given instance_id. - std::string InstanceName(std::string const& instance_id) const { - return google::cloud::bigtable::InstanceName(project_id_, instance_id); - } - - /// Return the fully qualified name of the given cluster_id in give - /// instance_id. - std::string ClusterName(std::string const& instance_id, - std::string const& cluster_id) const { - return google::cloud::bigtable::ClusterName(project_id_, instance_id, - cluster_id); - } - - std::string AppProfileName(std::string const& instance_id, - std::string const& profile_id) const { - return google::cloud::bigtable::AppProfileName(project_id_, instance_id, - profile_id); - } - - /** - * Create a new instance of Cloud Bigtable. - * - * @warning Note that this is operation can take seconds or minutes to - * complete. The application may prefer to perform other work while waiting - * for this operation. - * - * @param instance_config a description of the new instance to be created. - * instance_id and a display_name parameters must be set in instance_config, - * - instance_id : must be between 6 and 33 characters. - * - display_name : must be between 4 and 30 characters. - * @return a future that becomes satisfied when (a) the operation has - * completed successfully, in which case it returns a proto with the - * Instance details, (b) the operation has failed, in which case the future - * contains an `google::cloud::Status` with the details of the failure, or - * (c) the state of the operation is unknown after the time allocated by the - * retry policies has expired, in which case the future contains the last - * error status. - * - * @par Idempotency - * This operation is always treated as non-idempotent. - * - * @par Thread-safety - * Two threads concurrently calling this member function on the same instance - * of this class are **not** guaranteed to work. Consider copying the object - * and using different copies in each thread. - * - * @par Example - * @snippet bigtable_instance_admin_snippets.cc create instance - */ - future> CreateInstance( - InstanceConfig instance_config); - - /** - * Create a new Cluster of Cloud Bigtable. - * - * @param cluster_config a description of the new cluster to be created. - * @param instance_id the id of the instance in the project - * @param cluster_id the id of the cluster in the project that needs to be - * created. It must be between 6 and 30 characters. - * - * @par Idempotency - * This operation is always treated as non-idempotent. - * - * @par Thread-safety - * Two threads concurrently calling this member function on the same instance - * of this class are **not** guaranteed to work. Consider copying the object - * and using different copies in each thread. - * - * @par Example - * @snippet bigtable_instance_admin_snippets.cc create cluster - */ - future> CreateCluster( - ClusterConfig cluster_config, std::string const& instance_id, - std::string const& cluster_id); - - /** - * Update an existing instance of Cloud Bigtable. - * - * @warning Note that this is operation can take seconds or minutes to - * complete. The application may prefer to perform other work while waiting - * for this operation. - * - * @param instance_update_config config with modified instance. - * @return a future that becomes satisfied when (a) the operation has - * completed successfully, in which case it returns a proto with the - * Instance details, (b) the operation has failed, in which case the future - * contains an exception (typically `bigtable::GrpcError`) with the details - * of the failure, or (c) the state of the operation is unknown after the - * time allocated by the retry policies has expired, in which case the - * future contains an exception of type `bigtable::PollTimeout`. - * - * @par Idempotency - * This operation is always treated as non-idempotent. - * - * @par Thread-safety - * Two threads concurrently calling this member function on the same instance - * of this class are **not** guaranteed to work. Consider copying the object - * and using different copies in each thread. - * - * @par Example - * @snippet bigtable_instance_admin_snippets.cc update instance - */ - future> UpdateInstance( - InstanceUpdateConfig instance_update_config); - - /** - * Obtain the list of instances in the project. - * - * @note In some circumstances Cloud Bigtable may be unable to obtain the full - * list of instances, typically because some transient failure has made - * specific zones unavailable. In this cases the service returns a separate - * list of `failed_locations` that represent the unavailable zones. - * Applications may want to retry the operation after the transient - * conditions have cleared. - * - * @par Idempotency - * This operation is read-only and therefore it is always idempotent. - * - * @par Thread-safety - * Two threads concurrently calling this member function on the same instance - * of this class are **not** guaranteed to work. Consider copying the object - * and using different copies in each thread. - * - * @par Example - * @snippet bigtable_instance_admin_snippets.cc list instances - */ - StatusOr ListInstances(); - - /** - * Return the details of @p instance_id. - * - * @par Idempotency - * This operation is read-only and therefore it is always idempotent. - * - * @par Thread-safety - * Two threads concurrently calling this member function on the same instance - * of this class are **not** guaranteed to work. Consider copying the object - * and using different copies in each thread. - * - * @par Example - * @snippet bigtable_instance_admin_snippets.cc get instance - */ - StatusOr GetInstance( - std::string const& instance_id); - - /** - * Deletes the instances in the project. - * - * @param instance_id the id of the instance in the project that needs to be - * deleted - * - * @par Idempotency - * This operation is always treated as non-idempotent. - * - * @par Thread-safety - * Two threads concurrently calling this member function on the same instance - * of this class are **not** guaranteed to work. Consider copying the object - * and using different copies in each thread. - * - * @par Example - * @snippet bigtable_instance_admin_snippets.cc delete instance - */ - Status DeleteInstance(std::string const& instance_id); - - /** - * Obtain the list of clusters in an instance. - * - * @note In some circumstances Cloud Bigtable may be unable to obtain the full - * list of clusters, typically because some transient failure has made - * specific zones unavailable. In this cases the service returns a separate - * list of `failed_locations` that represent the unavailable zones. - * Applications may want to retry the operation after the transient - * conditions have cleared. - * - * @par Idempotency - * This operation is read-only and therefore it is always idempotent. - * - * @par Thread-safety - * Two threads concurrently calling this member function on the same instance - * of this class are **not** guaranteed to work. Consider copying the object - * and using different copies in each thread. - * - * @par Example - * @snippet bigtable_instance_admin_snippets.cc list clusters - */ - StatusOr ListClusters(); - - /** - * Obtain the list of clusters in an instance. - * - * @note In some circumstances Cloud Bigtable may be unable to obtain the full - * list of clusters, typically because some transient failure has made - * specific zones unavailable. In this cases the service returns a separate - * list of `failed_locations` that represent the unavailable zones. - * Applications may want to retry the operation after the transient - * conditions have cleared. - * - * @par Idempotency - * This operation is read-only and therefore it is always idempotent. - * - * @par Thread-safety - * Two threads concurrently calling this member function on the same instance - * of this class are **not** guaranteed to work. Consider copying the object - * and using different copies in each thread. - * - * @par Example - * @snippet bigtable_instance_admin_snippets.cc list clusters - */ - StatusOr ListClusters(std::string const& instance_id); - - /** - * Update an existing cluster of Cloud Bigtable. - * - * @warning Note that this is operation can take seconds or minutes to - * complete. The application may prefer to perform other work while waiting - * for this operation. - * - * @param cluster_config cluster with updated values. - * @return a future that becomes satisfied when (a) the operation has - * completed successfully, in which case it returns a proto with the - * Instance details, (b) the operation has failed, in which case the future - * contains an exception (typically `bigtable::GrpcError`) with the details - * of the failure, or (c) the state of the operation is unknown after the - * time allocated by the retry policies has expired, in which case the - * future contains an exception of type `bigtable::PollTimeout`. - * - * @par Idempotency - * This operation is always treated as non-idempotent. - * - * @par Thread-safety - * Two threads concurrently calling this member function on the same instance - * of this class are **not** guaranteed to work. Consider copying the object - * and using different copies in each thread. - * - * @par Example - * @snippet bigtable_instance_admin_snippets.cc update cluster - */ - future> UpdateCluster( - ClusterConfig cluster_config); - - /** - * Deletes the specified cluster of an instance in the project. - * - * @param instance_id the id of the instance in the project - * @param cluster_id the id of the cluster in the project that needs to be - * deleted - * - * @par Idempotency - * This operation is always treated as non-idempotent. - * - * @par Thread-safety - * Two threads concurrently calling this member function on the same instance - * of this class are **not** guaranteed to work. Consider copying the object - * and using different copies in each thread. - * - * @par Example - * @snippet bigtable_instance_admin_snippets.cc delete cluster - */ - Status DeleteCluster(std::string const& instance_id, - std::string const& cluster_id); - - /** - * Gets the specified cluster of an instance in the project. - * - * @param instance_id the id of the instance in the project - * @param cluster_id the id of the cluster in the project that needs to be - * deleted - * @return a Cluster for given instance_id and cluster_id. - * - * @par Idempotency - * This operation is read-only and therefore it is always idempotent. - * - * @par Thread-safety - * Two threads concurrently calling this member function on the same instance - * of this class are **not** guaranteed to work. Consider copying the object - * and using different copies in each thread. - * - * @par Example - * @snippet bigtable_instance_admin_snippets.cc get cluster - */ - StatusOr GetCluster( - std::string const& instance_id, std::string const& cluster_id); - - /** - * Create a new application profile. - * - * @param instance_id the instance for the new application profile. - * @param config the configuration for the new application profile. - * @return The proto describing the new application profile. - * - * @par Idempotency - * This operation is always treated as non-idempotent. - * - * @par Thread-safety - * Two threads concurrently calling this member function on the same instance - * of this class are **not** guaranteed to work. Consider copying the object - * and using different copies in each thread. - * - * @par Multi-cluster Routing Example - * @snippet bigtable_instance_admin_snippets.cc create app profile - * - * @par Single Cluster Routing Example - * @snippet bigtable_instance_admin_snippets.cc create app profile cluster - */ - StatusOr CreateAppProfile( - std::string const& instance_id, AppProfileConfig config); - - /** - * Fetch the detailed information about an existing application profile. - * - * @param instance_id the instance to look the profile in. - * @param profile_id the id of the profile within that instance. - * @return The proto describing the application profile. - * - * @par Idempotency - * This operation is read-only and therefore it is always idempotent. - * - * @par Thread-safety - * Two threads concurrently calling this member function on the same instance - * of this class are **not** guaranteed to work. Consider copying the object - * and using different copies in each thread. - * - * @par Example - * @snippet bigtable_instance_admin_snippets.cc get app profile - */ - StatusOr GetAppProfile( - std::string const& instance_id, std::string const& profile_id); - - /** - * Updates an existing application profile. - * - * @param instance_id the instance for the new application profile. - * @param profile_id the id (not the full name) of the profile to update. - * @param config the configuration for the new application profile. - * @return The proto describing the new application profile. - * - * @par Idempotency - * This operation is always treated as non-idempotent. - * - * @par Thread-safety - * Two threads concurrently calling this member function on the same instance - * of this class are **not** guaranteed to work. Consider copying the object - * and using different copies in each thread. - * - * @par Change Description Example - * @snippet bigtable_instance_admin_snippets.cc update app profile description - * - * @par Change Routing to Any Cluster Example - * @snippet bigtable_instance_admin_snippets.cc update app profile routing any - * - * @par Change Routing to a Specific Cluster Example - * @snippet bigtable_instance_admin_snippets.cc update app profile routing - */ - future> UpdateAppProfile( - std::string const& instance_id, std::string const& profile_id, - AppProfileUpdateConfig config); - - /** - * List the application profiles in an instance. - * - * @param instance_id the instance to list the profiles for. - * @return a std::vector with the protos describing any profiles. - * - * @par Idempotency - * This operation is read-only and therefore it is always idempotent. - * - * @par Thread-safety - * Two threads concurrently calling this member function on the same instance - * of this class are **not** guaranteed to work. Consider copying the object - * and using different copies in each thread. - * - * @par Example - * @snippet bigtable_instance_admin_snippets.cc list app profiles - */ - StatusOr> - ListAppProfiles(std::string const& instance_id); - - /** - * Delete an existing application profile. - * - * @param instance_id the instance to look the profile in. - * @param profile_id the id of the profile within that instance. - * @param ignore_warnings if true, ignore safety checks when deleting the - * application profile. This value is to to `true` by default. Passing - * `false` causes this function to fail even when no operations are - * pending. - * - * @par Idempotency - * This operation is always treated as non-idempotent. - * - * @par Thread-safety - * Two threads concurrently calling this member function on the same instance - * of this class are **not** guaranteed to work. Consider copying the object - * and using different copies in each thread. - * - * @par Example - * @snippet bigtable_instance_admin_snippets.cc delete app profile - */ - Status DeleteAppProfile(std::string const& instance_id, - std::string const& profile_id, - bool ignore_warnings = true); - - /** - * Gets the native policy for @p instance_id. - * - * @param instance_id the instance to query. - * @return google::iam::v1::Policy the full IAM policy for the instance. - * - * @par Idempotency - * This operation is read-only and therefore it is always idempotent. - * - * @par Thread-safety - * Two threads concurrently calling this member function on the same instance - * of this class are **not** guaranteed to work. Consider copying the object - * and using different copies in each thread. - * - * @par Example - * @snippet bigtable_instance_admin_snippets.cc get native iam policy - */ - StatusOr GetNativeIamPolicy( - std::string const& instance_id); - - /** - * Sets the IAM policy for an instance. - * - * @param instance_id which instance to set the IAM policy for. - * @param iam_policy google::iam::v1::Policy object containing role and - * members. - * @return google::iam::v1::Policy the current IAM policy for the instance. - * - * @warning ETags are currently not used by Cloud Bigtable. - * - * @par Idempotency - * This operation is always treated as non-idempotent. - * - * @par Thread-safety - * Two threads concurrently calling this member function on the same instance - * of this class are **not** guaranteed to work. Consider copying the object - * and using different copies in each thread. - * - * @par Example - * @snippet bigtable_instance_admin_snippets.cc set native iam policy - */ - StatusOr SetIamPolicy( - std::string const& instance_id, - google::iam::v1::Policy const& iam_policy); - - /** - * Returns a permission set that the caller has on the specified instance. - * - * @param instance_id the ID of the instance to query. - * @param permissions set of permissions to check for the resource. - * - * @par Idempotency - * This operation is read-only and therefore it is always idempotent. - * - * @par Thread-safety - * Two threads concurrently calling this member function on the same instance - * of this class are **not** guaranteed to work. Consider copying the object - * and using different copies in each thread. - * - * @par Example - * @snippet bigtable_instance_admin_snippets.cc test iam permissions - * - * @see https://cloud.google.com/bigtable/docs/access-control for a list of - * valid permissions on Google Cloud Bigtable. - */ - StatusOr> TestIamPermissions( - std::string const& instance_id, - std::vector const& permissions); - - private: - friend class bigtable_internal::InstanceAdminTester; - - ///@{ - /// @name Helper functions to implement constructors with changed policies. - void ChangePolicy(RPCRetryPolicy const& policy) { - retry_prototype_ = policy.clone(); - } - - void ChangePolicy(RPCBackoffPolicy const& policy) { - backoff_prototype_ = policy.clone(); - } - - void ChangePolicy(PollingPolicy const& policy) { - polling_prototype_ = policy.clone(); - } - - template - void ChangePolicies(Policy&& policy, Policies&&... policies) { - ChangePolicy(policy); - ChangePolicies(std::forward(policies)...); - } - void ChangePolicies() {} - ///@} - - std::shared_ptr connection_; - std::string project_id_; - std::string project_name_; - ///@{ - /// These prototypes are only used as temporary storage during construction of - /// the class, where they are consolidated as common policies in `options_`. - std::shared_ptr retry_prototype_; - std::shared_ptr backoff_prototype_; - std::shared_ptr polling_prototype_; - ///} - Options options_; -}; - -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END -} // namespace bigtable -} // namespace cloud -} // namespace google - -#endif // GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_INSTANCE_ADMIN_H diff --git a/google/cloud/bigtable/instance_admin_client.cc b/google/cloud/bigtable/instance_admin_client.cc deleted file mode 100644 index 1309858e2d537..0000000000000 --- a/google/cloud/bigtable/instance_admin_client.cc +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2018 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 -// -// https://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. - -#include "google/cloud/bigtable/instance_admin_client.h" -#include "google/cloud/bigtable/internal/defaults.h" - -namespace google { -namespace cloud { -namespace bigtable { -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN - -std::shared_ptr MakeInstanceAdminClient( - std::string project, Options options) { - options = internal::DefaultInstanceAdminOptions(std::move(options)); - return std::shared_ptr( - new InstanceAdminClient(std::move(project), std::move(options))); -} - -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END -} // namespace bigtable -} // namespace cloud -} // namespace google diff --git a/google/cloud/bigtable/instance_admin_client.h b/google/cloud/bigtable/instance_admin_client.h deleted file mode 100644 index e5c9e1acfb394..0000000000000 --- a/google/cloud/bigtable/instance_admin_client.h +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2018 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 -// -// https://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. - -#ifndef GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_INSTANCE_ADMIN_CLIENT_H -#define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_INSTANCE_ADMIN_CLIENT_H - -#include "google/cloud/bigtable/admin/bigtable_instance_admin_connection.h" -#include "google/cloud/bigtable/version.h" -#include -#include - -namespace google { -namespace cloud { -namespace bigtable { -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN - -/** - * Creates a `bigtable_admin::BigtableInstanceAdminConnection` for - * `bigtable::InstanceAdmin` to use. - * - * This class is used to initiate a connection to the Cloud Bigtable Instance - * Admin service. It is maintained only for backwards compatibility. - * - * @deprecated Please use `bigtable_admin::BigtableInstanceAdminConnection` to - * configure `bigtable_admin::BigtableInstanceAdminClient`, instead of using - * this class to configure `bigtable::InstanceAdmin`. - */ -class InstanceAdminClient final { - public: - virtual ~InstanceAdminClient() = default; - - /// The project id that this AdminClient works on. - virtual std::string const& project() { return project_; } - - private: - friend class InstanceAdmin; - friend std::shared_ptr MakeInstanceAdminClient( - std::string, Options); - - InstanceAdminClient(std::string project, Options options) - : project_(std::move(project)), - connection_(bigtable_admin::MakeBigtableInstanceAdminConnection( - std::move(options))) {} - - std::string project_; - std::shared_ptr connection_; -}; - -/// Create a new instance admin client configured via @p options. -std::shared_ptr MakeInstanceAdminClient( - std::string project, Options options = {}); - -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END -} // namespace bigtable -} // namespace cloud -} // namespace google - -#endif // GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_INSTANCE_ADMIN_CLIENT_H diff --git a/google/cloud/bigtable/instance_admin_client_test.cc b/google/cloud/bigtable/instance_admin_client_test.cc deleted file mode 100644 index a6cff0f75240a..0000000000000 --- a/google/cloud/bigtable/instance_admin_client_test.cc +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2018 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 -// -// https://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. - -#include "google/cloud/bigtable/instance_admin_client.h" -#include - -namespace google { -namespace cloud { -namespace bigtable { -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN -namespace { - -TEST(InstanceAdminClientTest, MakeClient) { - auto admin_client = MakeInstanceAdminClient("test-project"); - ASSERT_TRUE(admin_client); - EXPECT_EQ("test-project", admin_client->project()); -} - -} // namespace -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END -} // namespace bigtable -} // namespace cloud -} // namespace google diff --git a/google/cloud/bigtable/instance_admin_test.cc b/google/cloud/bigtable/instance_admin_test.cc deleted file mode 100644 index 433eb80c5dc89..0000000000000 --- a/google/cloud/bigtable/instance_admin_test.cc +++ /dev/null @@ -1,694 +0,0 @@ -// Copyright 2022 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 -// -// https://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. - -#include "google/cloud/bigtable/instance_admin.h" -#include "google/cloud/bigtable/admin/mocks/mock_bigtable_instance_admin_connection.h" -#include "google/cloud/bigtable/testing/mock_policies.h" -#include "google/cloud/grpc_options.h" -#include "google/cloud/location.h" -#include "google/cloud/project.h" -#include "google/cloud/testing_util/status_matchers.h" -#include - -namespace google { -namespace cloud { -namespace bigtable_internal { -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN - -// Helper class for checking that the legacy API still functions correctly -class InstanceAdminTester { - public: - static std::shared_ptr - Connection(bigtable::InstanceAdmin const& admin) { - return admin.connection_; - } - - static ::google::cloud::Options Options( - bigtable::InstanceAdmin const& admin) { - return admin.options_; - } -}; - -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END -} // namespace bigtable_internal -namespace bigtable { -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN -namespace { - -namespace btadmin = ::google::bigtable::admin::v2; -namespace iamproto = ::google::iam::v1; - -using ::google::cloud::bigtable::testing::MockBackoffPolicy; -using ::google::cloud::bigtable::testing::MockPollingPolicy; -using ::google::cloud::bigtable::testing::MockRetryPolicy; -using ::google::cloud::bigtable_internal::InstanceAdminTester; -using ::google::cloud::testing_util::StatusIs; -using ::testing::An; -using ::testing::Contains; -using ::testing::ElementsAreArray; -using ::testing::NotNull; -using ::testing::Return; -using ::testing::UnorderedElementsAreArray; - -using MockConnection = - ::google::cloud::bigtable_admin_mocks::MockBigtableInstanceAdminConnection; - -auto const kProjectId = "the-project"; -auto const kInstanceId = "the-instance"; -auto const kClusterId = "the-cluster"; -auto const kProfileId = "the-profile"; -auto const kProjectName = "projects/the-project"; -auto const kInstanceName = "projects/the-project/instances/the-instance"; -auto const kClusterName = - "projects/the-project/instances/the-instance/clusters/the-cluster"; -auto const kProfileName = - "projects/the-project/instances/the-instance/appProfiles/the-profile"; - -std::string LocationName(std::string const& location) { - return Location(Project(kProjectId), location).FullName(); -} - -Status FailingStatus() { return Status(StatusCode::kPermissionDenied, "fail"); } - -struct TestOption { - using Type = int; -}; - -Options TestOptions() { - return Options{} - .set(grpc::InsecureChannelCredentials()) - .set(1); -} - -void CheckOptions(Options const& options) { - EXPECT_TRUE( - options.has()); - EXPECT_TRUE( - options.has()); - EXPECT_TRUE( - options.has()); - EXPECT_TRUE(options.has()); - EXPECT_TRUE(options.has()); - EXPECT_TRUE(options.has()); -} - -/// A fixture for the bigtable::InstanceAdmin tests. -class InstanceAdminTest : public ::testing::Test { - protected: - InstanceAdmin DefaultInstanceAdmin() { - EXPECT_CALL(*connection_, options()) - .WillRepeatedly(Return(Options{}.set(1))); - return InstanceAdmin(connection_, kProjectId); - } - - std::shared_ptr connection_ = - std::make_shared(); -}; - -TEST_F(InstanceAdminTest, Project) { - InstanceAdmin tested(MakeInstanceAdminClient(kProjectId, TestOptions())); - EXPECT_EQ(kProjectId, tested.project_id()); - EXPECT_EQ(kProjectName, tested.project_name()); -} - -TEST_F(InstanceAdminTest, CopyConstructor) { - auto source = InstanceAdmin(connection_, kProjectId); - std::string const& expected = source.project_id(); - // NOLINTNEXTLINE(performance-unnecessary-copy-initialization) - InstanceAdmin copy(source); - EXPECT_EQ(expected, copy.project_id()); -} - -TEST_F(InstanceAdminTest, MoveConstructor) { - auto source = InstanceAdmin(connection_, kProjectId); - std::string expected = source.project_id(); - InstanceAdmin copy(std::move(source)); - EXPECT_EQ(expected, copy.project_id()); -} - -TEST_F(InstanceAdminTest, CopyAssignment) { - std::shared_ptr other_client = - std::make_shared(); - - auto source = InstanceAdmin(connection_, kProjectId); - std::string const& expected = source.project_id(); - auto dest = InstanceAdmin(other_client, "other-project"); - EXPECT_NE(expected, dest.project_id()); - dest = source; - EXPECT_EQ(expected, dest.project_id()); -} - -TEST_F(InstanceAdminTest, MoveAssignment) { - std::shared_ptr other_client = - std::make_shared(); - - auto source = InstanceAdmin(connection_, kProjectId); - std::string expected = source.project_id(); - auto dest = InstanceAdmin(other_client, "other-project"); - EXPECT_NE(expected, dest.project_id()); - dest = std::move(source); - EXPECT_EQ(expected, dest.project_id()); -} - -TEST_F(InstanceAdminTest, WithNewTarget) { - auto admin = InstanceAdmin(connection_, kProjectId); - auto other_admin = admin.WithNewTarget("other-project"); - EXPECT_EQ(other_admin.project_id(), "other-project"); - EXPECT_EQ(other_admin.project_name(), Project("other-project").FullName()); -} - -TEST_F(InstanceAdminTest, LegacyConstructorSharesConnection) { - auto admin_client = MakeInstanceAdminClient("test-project", TestOptions()); - auto admin_1 = InstanceAdmin(admin_client); - auto admin_2 = InstanceAdmin(admin_client); - auto conn_1 = InstanceAdminTester::Connection(admin_1); - auto conn_2 = InstanceAdminTester::Connection(admin_2); - - EXPECT_EQ(conn_1, conn_2); - EXPECT_THAT(conn_1, NotNull()); -} - -TEST_F(InstanceAdminTest, LegacyConstructorDefaultsPolicies) { - auto admin_client = MakeInstanceAdminClient("test-project", TestOptions()); - auto admin = InstanceAdmin(std::move(admin_client)); - auto options = InstanceAdminTester::Options(admin); - CheckOptions(options); -} - -TEST_F(InstanceAdminTest, LegacyConstructorWithPolicies) { - // In this test, we make a series of simple calls to verify that the policies - // passed to the `InstanceAdmin` constructor are actually collected as - // `Options`. - // - // Upon construction of an InstanceAdmin, each policy is cloned twice: Once - // while processing the variadic parameters, once while converting from - // Bigtable policies to common policies. This should explain the nested mocks - // below. - - auto mock_r = std::make_shared(); - auto mock_b = std::make_shared(); - auto mock_p = std::make_shared(); - - EXPECT_CALL(*mock_r, clone).WillOnce([] { - auto clone_1 = std::make_unique(); - EXPECT_CALL(*clone_1, clone).WillOnce([] { - auto clone_2 = std::make_unique(); - EXPECT_CALL(*clone_2, OnFailure(An())); - return clone_2; - }); - return clone_1; - }); - - EXPECT_CALL(*mock_b, clone).WillOnce([] { - auto clone_1 = std::make_unique(); - EXPECT_CALL(*clone_1, clone).WillOnce([] { - auto clone_2 = std::make_unique(); - EXPECT_CALL(*clone_2, OnCompletion(An())); - return clone_2; - }); - return clone_1; - }); - - EXPECT_CALL(*mock_p, clone).WillOnce([] { - auto clone_1 = std::make_unique(); - EXPECT_CALL(*clone_1, clone).WillOnce([] { - auto clone_2 = std::make_unique(); - EXPECT_CALL(*clone_2, WaitPeriod); - return clone_2; - }); - return clone_1; - }); - - auto admin_client = MakeInstanceAdminClient("test-project", TestOptions()); - auto admin = - InstanceAdmin(std::move(admin_client), *mock_r, *mock_b, *mock_p); - auto options = InstanceAdminTester::Options(admin); - CheckOptions(options); - - auto const& common_retry = - options.get(); - (void)common_retry->OnFailure({}); - - auto const& common_backoff = - options.get(); - (void)common_backoff->OnCompletion(); - - auto const& common_polling = - options.get(); - (void)common_polling->WaitPeriod(); -} - -TEST_F(InstanceAdminTest, ListInstancesSuccess) { - auto tested = DefaultInstanceAdmin(); - std::vector const expected_names = { - InstanceName(kProjectId, "i0"), InstanceName(kProjectId, "i1")}; - std::vector const expected_fails = {"l0", "l1"}; - - EXPECT_CALL(*connection_, ListInstances) - .WillOnce([&expected_names, &expected_fails]( - btadmin::ListInstancesRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - EXPECT_EQ(kProjectName, request.parent()); - - btadmin::ListInstancesResponse response; - for (auto const& name : expected_names) { - auto& instance = *response.add_instances(); - instance.set_name(name); - } - for (auto const& loc : expected_fails) { - *response.add_failed_locations() = loc; - } - return make_status_or(response); - }); - - auto actual = tested.ListInstances(); - ASSERT_STATUS_OK(actual); - std::vector actual_names; - std::transform(actual->instances.begin(), actual->instances.end(), - std::back_inserter(actual_names), - [](btadmin::Instance const& i) { return i.name(); }); - - EXPECT_THAT(actual_names, ElementsAreArray(expected_names)); - EXPECT_THAT(actual->failed_locations, ElementsAreArray(expected_fails)); -} - -TEST_F(InstanceAdminTest, ListInstancesFailure) { - auto tested = DefaultInstanceAdmin(); - - EXPECT_CALL(*connection_, ListInstances).WillOnce(Return(FailingStatus())); - - EXPECT_THAT(tested.ListInstances(), StatusIs(StatusCode::kPermissionDenied)); -} - -TEST_F(InstanceAdminTest, CreateInstance) { - auto tested = DefaultInstanceAdmin(); - auto constexpr kDisplayName = "display name"; - std::vector const expected_location_names = {LocationName("l0"), - LocationName("l1")}; - std::map cluster_map = { - {"c0", ClusterConfig("l0", 3, btadmin::HDD)}, - {"c1", ClusterConfig("l1", 3, btadmin::HDD)}}; - auto config = InstanceConfig(kInstanceId, kDisplayName, cluster_map); - - EXPECT_CALL(*connection_, - CreateInstance(An())) - .WillOnce([&](btadmin::CreateInstanceRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - EXPECT_EQ(kInstanceId, request.instance_id()); - EXPECT_EQ(kProjectName, request.parent()); - EXPECT_EQ(kDisplayName, request.instance().display_name()); - std::vector actual_location_names; - for (auto&& c : request.clusters()) { - actual_location_names.emplace_back(c.second.location()); - } - EXPECT_THAT(actual_location_names, - UnorderedElementsAreArray(expected_location_names)); - return make_ready_future>(FailingStatus()); - }); - - EXPECT_THAT(tested.CreateInstance(config).get(), - StatusIs(StatusCode::kPermissionDenied)); -} - -TEST_F(InstanceAdminTest, CreateCluster) { - auto tested = DefaultInstanceAdmin(); - auto const location_name = LocationName("the-location"); - auto config = ClusterConfig("the-location", 3, btadmin::HDD); - - EXPECT_CALL(*connection_, - CreateCluster(An())) - .WillOnce([&](btadmin::CreateClusterRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - EXPECT_EQ(kClusterId, request.cluster_id()); - EXPECT_EQ(kInstanceName, request.parent()); - EXPECT_EQ(location_name, request.cluster().location()); - EXPECT_EQ(3, request.cluster().serve_nodes()); - EXPECT_EQ(btadmin::HDD, request.cluster().default_storage_type()); - return make_ready_future>(FailingStatus()); - }); - - EXPECT_THAT(tested.CreateCluster(config, kInstanceId, kClusterId).get(), - StatusIs(StatusCode::kPermissionDenied)); -} - -TEST_F(InstanceAdminTest, UpdateInstance) { - auto tested = DefaultInstanceAdmin(); - auto constexpr kDisplayName = "updated display name"; - InstanceUpdateConfig config({}); - config.set_display_name(kDisplayName); - - EXPECT_CALL( - *connection_, - PartialUpdateInstance(An())) - .WillOnce([&](btadmin::PartialUpdateInstanceRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - EXPECT_EQ(kDisplayName, request.instance().display_name()); - EXPECT_THAT(request.update_mask().paths(), Contains("display_name")); - return make_ready_future>(FailingStatus()); - }); - - EXPECT_THAT(tested.UpdateInstance(config).get(), - StatusIs(StatusCode::kPermissionDenied)); -} - -TEST_F(InstanceAdminTest, GetInstance) { - auto tested = DefaultInstanceAdmin(); - - EXPECT_CALL(*connection_, GetInstance) - .WillOnce([&](btadmin::GetInstanceRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - EXPECT_EQ(kInstanceName, request.name()); - return FailingStatus(); - }); - - EXPECT_THAT(tested.GetInstance(kInstanceId), - StatusIs(StatusCode::kPermissionDenied)); -} - -TEST_F(InstanceAdminTest, DeleteInstance) { - auto tested = DefaultInstanceAdmin(); - - EXPECT_CALL(*connection_, DeleteInstance) - .WillOnce([&](btadmin::DeleteInstanceRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - EXPECT_EQ(kInstanceName, request.name()); - return Status(); - }); - - EXPECT_STATUS_OK(tested.DeleteInstance(kInstanceId)); -} - -TEST_F(InstanceAdminTest, GetCluster) { - auto tested = DefaultInstanceAdmin(); - - EXPECT_CALL(*connection_, GetCluster) - .WillOnce([&](btadmin::GetClusterRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - EXPECT_EQ(kClusterName, request.name()); - return FailingStatus(); - }); - - EXPECT_THAT(tested.GetCluster(kInstanceId, kClusterId), - StatusIs(StatusCode::kPermissionDenied)); -} - -TEST_F(InstanceAdminTest, ListClustersSuccess) { - auto tested = DefaultInstanceAdmin(); - std::vector const expected_names = { - ClusterName(kProjectId, kInstanceId, "c0"), - ClusterName(kProjectId, kInstanceId, "c1")}; - std::vector const expected_fails = {"l0", "l1"}; - - EXPECT_CALL(*connection_, ListClusters) - .WillOnce([&](btadmin::ListClustersRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - EXPECT_EQ(kInstanceName, request.parent()); - - btadmin::ListClustersResponse response; - for (auto const& name : expected_names) { - auto& cluster = *response.add_clusters(); - cluster.set_name(name); - } - for (auto const& loc : expected_fails) { - *response.add_failed_locations() = loc; - } - return make_status_or(response); - }); - - auto actual = tested.ListClusters(kInstanceId); - ASSERT_STATUS_OK(actual); - std::vector actual_names; - std::transform(actual->clusters.begin(), actual->clusters.end(), - std::back_inserter(actual_names), - [](btadmin::Cluster const& c) { return c.name(); }); - - EXPECT_THAT(actual_names, ElementsAreArray(expected_names)); - EXPECT_THAT(actual->failed_locations, ElementsAreArray(expected_fails)); -} - -TEST_F(InstanceAdminTest, ListClustersFailure) { - auto tested = DefaultInstanceAdmin(); - - EXPECT_CALL(*connection_, ListClusters) - .WillOnce([&](btadmin::ListClustersRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - // Verify that calling `ListClusters` with no arguments sets the - // instance-id to "-" - auto const instance_name = InstanceName(kProjectId, "-"); - EXPECT_EQ(instance_name, request.parent()); - return FailingStatus(); - }); - - EXPECT_THAT(tested.ListClusters(), StatusIs(StatusCode::kPermissionDenied)); -} - -TEST_F(InstanceAdminTest, UpdateCluster) { - auto tested = DefaultInstanceAdmin(); - auto const location_name = LocationName("the-location"); - btadmin::Cluster c; - c.set_name(kClusterName); - c.set_location(location_name); - c.set_serve_nodes(3); - c.set_default_storage_type(btadmin::HDD); - auto config = ClusterConfig(std::move(c)); - - EXPECT_CALL(*connection_, UpdateCluster(An())) - .WillOnce([&](btadmin::Cluster const& cluster) { - CheckOptions(google::cloud::internal::CurrentOptions()); - EXPECT_EQ(kClusterName, cluster.name()); - EXPECT_EQ(location_name, cluster.location()); - EXPECT_EQ(3, cluster.serve_nodes()); - EXPECT_EQ(btadmin::HDD, cluster.default_storage_type()); - return make_ready_future>(FailingStatus()); - }); - - EXPECT_THAT(tested.UpdateCluster(config).get(), - StatusIs(StatusCode::kPermissionDenied)); -} - -TEST_F(InstanceAdminTest, DeleteCluster) { - auto tested = DefaultInstanceAdmin(); - - EXPECT_CALL(*connection_, DeleteCluster) - .WillOnce([&](btadmin::DeleteClusterRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - EXPECT_EQ(kClusterName, request.name()); - return Status(); - }); - - EXPECT_STATUS_OK(tested.DeleteCluster(kInstanceId, kClusterId)); -} - -TEST_F(InstanceAdminTest, CreateAppProfile) { - auto tested = DefaultInstanceAdmin(); - auto config = AppProfileConfig::MultiClusterUseAny(kProfileId); - - EXPECT_CALL(*connection_, CreateAppProfile) - .WillOnce([&](btadmin::CreateAppProfileRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - EXPECT_EQ(kProfileId, request.app_profile_id()); - EXPECT_EQ(kInstanceName, request.parent()); - return FailingStatus(); - }); - - EXPECT_THAT(tested.CreateAppProfile(kInstanceId, config), - StatusIs(StatusCode::kPermissionDenied)); -} - -TEST_F(InstanceAdminTest, GetAppProfile) { - auto tested = DefaultInstanceAdmin(); - - EXPECT_CALL(*connection_, GetAppProfile) - .WillOnce([&](btadmin::GetAppProfileRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - EXPECT_EQ(kProfileName, request.name()); - return FailingStatus(); - }); - - EXPECT_THAT(tested.GetAppProfile(kInstanceId, kProfileId), - StatusIs(StatusCode::kPermissionDenied)); -} - -TEST_F(InstanceAdminTest, UpdateAppProfile) { - auto tested = DefaultInstanceAdmin(); - auto constexpr kDescription = "description"; - auto config = AppProfileUpdateConfig().set_description(kDescription); - - EXPECT_CALL(*connection_, - UpdateAppProfile(An())) - .WillOnce([&](btadmin::UpdateAppProfileRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - EXPECT_EQ(kProfileName, request.app_profile().name()); - EXPECT_EQ(kDescription, request.app_profile().description()); - return make_ready_future>( - FailingStatus()); - }); - - EXPECT_THAT(tested.UpdateAppProfile(kInstanceId, kProfileId, config).get(), - StatusIs(StatusCode::kPermissionDenied)); -} - -TEST_F(InstanceAdminTest, ListAppProfilesSuccess) { - auto tested = DefaultInstanceAdmin(); - std::vector const expected_names = { - AppProfileName(kProjectId, kInstanceId, "p0"), - AppProfileName(kProjectId, kInstanceId, "p1")}; - - auto iter = expected_names.begin(); - EXPECT_CALL(*connection_, ListAppProfiles) - .WillOnce([&iter, &expected_names]( - btadmin::ListAppProfilesRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - EXPECT_EQ(kInstanceName, request.parent()); - - using ::google::cloud::internal::MakeStreamRange; - using ::google::cloud::internal::StreamReader; - auto reader = [&iter, &expected_names]() - -> StreamReader::result_type { - if (iter != expected_names.end()) { - btadmin::AppProfile p; - p.set_name(*iter); - ++iter; - return p; - } - return Status(); - }; - return MakeStreamRange(std::move(reader)); - }); - - auto profiles = tested.ListAppProfiles(kInstanceId); - ASSERT_STATUS_OK(profiles); - std::vector names; - std::transform(profiles->begin(), profiles->end(), std::back_inserter(names), - [](btadmin::AppProfile const& p) { return p.name(); }); - - EXPECT_THAT(names, ElementsAreArray(expected_names)); -} - -TEST_F(InstanceAdminTest, ListAppProfilesFailure) { - auto tested = DefaultInstanceAdmin(); - - EXPECT_CALL(*connection_, ListAppProfiles) - .WillOnce([&](btadmin::ListAppProfilesRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - EXPECT_EQ(kInstanceName, request.parent()); - - using ::google::cloud::internal::MakeStreamRange; - return MakeStreamRange( - [] { return FailingStatus(); }); - }); - - EXPECT_THAT(tested.ListAppProfiles(kInstanceId), - StatusIs(StatusCode::kPermissionDenied)); -} - -TEST_F(InstanceAdminTest, DeleteAppProfile) { - auto tested = DefaultInstanceAdmin(); - - EXPECT_CALL(*connection_, DeleteAppProfile) - .WillOnce([&](btadmin::DeleteAppProfileRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - EXPECT_EQ(kProfileName, request.name()); - EXPECT_EQ(true, request.ignore_warnings()); - return Status(); - }); - - EXPECT_STATUS_OK(tested.DeleteAppProfile(kInstanceId, kProfileId, true)); -} - -TEST_F(InstanceAdminTest, GetNativeIamPolicy) { - auto tested = DefaultInstanceAdmin(); - - EXPECT_CALL(*connection_, GetIamPolicy) - .WillOnce([&](iamproto::GetIamPolicyRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - EXPECT_EQ(kInstanceName, request.resource()); - return FailingStatus(); - }); - - EXPECT_THAT(tested.GetNativeIamPolicy(kInstanceId), - StatusIs(StatusCode::kPermissionDenied)); -} - -TEST_F(InstanceAdminTest, SetNativeIamPolicy) { - auto tested = DefaultInstanceAdmin(); - iamproto::Policy policy; - policy.set_etag("tag"); - policy.set_version(3); - - EXPECT_CALL(*connection_, SetIamPolicy) - .WillOnce([&](iamproto::SetIamPolicyRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - EXPECT_EQ(kInstanceName, request.resource()); - EXPECT_EQ("tag", request.policy().etag()); - EXPECT_EQ(3, request.policy().version()); - return FailingStatus(); - }); - - EXPECT_THAT(tested.SetIamPolicy(kInstanceId, policy), - StatusIs(StatusCode::kPermissionDenied)); -} - -TEST_F(InstanceAdminTest, TestIamPermissionsSuccess) { - auto tested = DefaultInstanceAdmin(); - std::vector const expected_permissions = {"writer", "reader"}; - std::vector const returned_permissions = {"reader"}; - - EXPECT_CALL(*connection_, TestIamPermissions) - .WillOnce([&](iamproto::TestIamPermissionsRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - EXPECT_EQ(kInstanceName, request.resource()); - std::vector actual_permissions; - for (auto const& c : request.permissions()) { - actual_permissions.emplace_back(c); - } - EXPECT_THAT(actual_permissions, - UnorderedElementsAreArray(expected_permissions)); - - iamproto::TestIamPermissionsResponse r; - for (auto const& p : returned_permissions) r.add_permissions(p); - return r; - }); - - auto resp = tested.TestIamPermissions(kInstanceId, expected_permissions); - ASSERT_STATUS_OK(resp); - EXPECT_THAT(*resp, ElementsAreArray(returned_permissions)); -} - -TEST_F(InstanceAdminTest, TestIamPermissionsFailure) { - auto tested = DefaultInstanceAdmin(); - std::vector const expected_permissions = {"writer", "reader"}; - - EXPECT_CALL(*connection_, TestIamPermissions) - .WillOnce([&](iamproto::TestIamPermissionsRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - EXPECT_EQ(kInstanceName, request.resource()); - std::vector actual_permissions; - for (auto const& c : request.permissions()) { - actual_permissions.emplace_back(c); - } - EXPECT_THAT(actual_permissions, - UnorderedElementsAreArray(expected_permissions)); - return FailingStatus(); - }); - - EXPECT_THAT(tested.TestIamPermissions(kInstanceId, expected_permissions), - StatusIs(StatusCode::kPermissionDenied)); -} - -} // namespace -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END -} // namespace bigtable -} // namespace cloud -} // namespace google diff --git a/google/cloud/bigtable/table_admin.cc b/google/cloud/bigtable/table_admin.cc deleted file mode 100644 index fb7758553c062..0000000000000 --- a/google/cloud/bigtable/table_admin.cc +++ /dev/null @@ -1,349 +0,0 @@ -// Copyright 2017 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 -// -// https://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. - -#include "google/cloud/bigtable/table_admin.h" -#include "google/cloud/bigtable/admin/bigtable_table_admin_client.h" -#include "google/cloud/bigtable/wait_for_consistency.h" -#include "google/cloud/internal/time_utils.h" -#include "google/protobuf/duration.pb.h" -#include - -namespace btadmin = ::google::bigtable::admin::v2; - -namespace google { -namespace cloud { -namespace bigtable { -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN -static_assert(std::is_copy_constructible::value, - "bigtable::TableAdmin must be constructible"); -static_assert(std::is_copy_assignable::value, - "bigtable::TableAdmin must be assignable"); - -// NOLINTNEXTLINE(readability-identifier-naming) -constexpr TableAdmin::TableView TableAdmin::ENCRYPTION_VIEW; -// NOLINTNEXTLINE(readability-identifier-naming) -constexpr TableAdmin::TableView TableAdmin::FULL; -// NOLINTNEXTLINE(readability-identifier-naming) -constexpr TableAdmin::TableView TableAdmin::NAME_ONLY; -// NOLINTNEXTLINE(readability-identifier-naming) -constexpr TableAdmin::TableView TableAdmin::REPLICATION_VIEW; -// NOLINTNEXTLINE(readability-identifier-naming) -constexpr TableAdmin::TableView TableAdmin::SCHEMA_VIEW; -// NOLINTNEXTLINE(readability-identifier-naming) -constexpr TableAdmin::TableView TableAdmin::VIEW_UNSPECIFIED; - -StatusOr TableAdmin::CreateTable(std::string table_id, - TableConfig config) { - google::cloud::internal::OptionsSpan span(options_); - auto request = std::move(config).as_proto(); - request.set_parent(instance_name()); - request.set_table_id(std::move(table_id)); - return connection_->CreateTable(request); -} - -StatusOr> TableAdmin::ListTables( - btadmin::Table::View view) { - google::cloud::internal::OptionsSpan span(options_); - std::vector result; - - btadmin::ListTablesRequest request; - request.set_parent(instance_name()); - request.set_view(view); - auto sr = connection_->ListTables(request); - for (auto& t : sr) { - if (!t) return std::move(t).status(); - result.emplace_back(*std::move(t)); - } - return result; -} - -StatusOr TableAdmin::GetTable(std::string const& table_id, - btadmin::Table::View view) { - google::cloud::internal::OptionsSpan span(options_); - btadmin::GetTableRequest request; - request.set_name(TableName(table_id)); - request.set_view(view); - return connection_->GetTable(request); -} - -Status TableAdmin::DeleteTable(std::string const& table_id) { - google::cloud::internal::OptionsSpan span(options_); - btadmin::DeleteTableRequest request; - request.set_name(TableName(table_id)); - return connection_->DeleteTable(request); -} - -btadmin::CreateBackupRequest TableAdmin::CreateBackupParams::AsProto( - std::string instance_name) const { - btadmin::CreateBackupRequest proto; - proto.set_parent(instance_name + "/clusters/" + cluster_id); - proto.set_backup_id(backup_id); - proto.mutable_backup()->set_source_table(std::move(instance_name) + - "/tables/" + table_name); - *proto.mutable_backup()->mutable_expire_time() = - google::cloud::internal::ToProtoTimestamp(expire_time); - return proto; -} - -StatusOr TableAdmin::CreateBackup( - CreateBackupParams const& params) { - google::cloud::internal::OptionsSpan span(options_); - auto request = params.AsProto(instance_name()); - return connection_->CreateBackup(request).get(); -} - -StatusOr TableAdmin::GetBackup(std::string const& cluster_id, - std::string const& backup_id) { - google::cloud::internal::OptionsSpan span(options_); - btadmin::GetBackupRequest request; - request.set_name(BackupName(cluster_id, backup_id)); - return connection_->GetBackup(request); -} - -btadmin::UpdateBackupRequest TableAdmin::UpdateBackupParams::AsProto( - std::string const& instance_name) const { - btadmin::UpdateBackupRequest proto; - proto.mutable_backup()->set_name(instance_name + "/clusters/" + cluster_id + - "/backups/" + backup_name); - *proto.mutable_backup()->mutable_expire_time() = - google::cloud::internal::ToProtoTimestamp(expire_time); - proto.mutable_update_mask()->add_paths("expire_time"); - return proto; -} - -StatusOr TableAdmin::UpdateBackup( - UpdateBackupParams const& params) { - google::cloud::internal::OptionsSpan span(options_); - btadmin::UpdateBackupRequest request = params.AsProto(instance_name()); - return connection_->UpdateBackup(request); -} - -Status TableAdmin::DeleteBackup(btadmin::Backup const& backup) { - google::cloud::internal::OptionsSpan span(options_); - btadmin::DeleteBackupRequest request; - request.set_name(backup.name()); - return connection_->DeleteBackup(request); -} - -Status TableAdmin::DeleteBackup(std::string const& cluster_id, - std::string const& backup_id) { - google::cloud::internal::OptionsSpan span(options_); - btadmin::DeleteBackupRequest request; - request.set_name(BackupName(cluster_id, backup_id)); - return connection_->DeleteBackup(request); -} - -btadmin::ListBackupsRequest TableAdmin::ListBackupsParams::AsProto( - std::string const& instance_name) const { - btadmin::ListBackupsRequest proto; - proto.set_parent(cluster_id ? instance_name + "/clusters/" + *cluster_id - : instance_name + "/clusters/-"); - if (filter) *proto.mutable_filter() = *filter; - if (order_by) *proto.mutable_order_by() = *order_by; - return proto; -} - -StatusOr> TableAdmin::ListBackups( - ListBackupsParams const& params) { - google::cloud::internal::OptionsSpan span(options_); - std::vector result; - - btadmin::ListBackupsRequest request = params.AsProto(instance_name()); - auto sr = connection_->ListBackups(request); - for (auto& b : sr) { - if (!b) return std::move(b).status(); - result.emplace_back(*std::move(b)); - } - return result; -} - -btadmin::RestoreTableRequest TableAdmin::RestoreTableParams::AsProto( - std::string const& instance_name) const { - btadmin::RestoreTableRequest proto; - proto.set_parent(instance_name); - proto.set_table_id(table_id); - proto.set_backup(instance_name + "/clusters/" + cluster_id + "/backups/" + - backup_id); - return proto; -} - -StatusOr TableAdmin::RestoreTable( - RestoreTableParams const& params) { - auto p = RestoreTableFromInstanceParams{ - params.table_id, BackupName(params.cluster_id, params.backup_id)}; - return RestoreTable(std::move(p)); -} - -btadmin::RestoreTableRequest AsProto( - std::string const& instance_name, - TableAdmin::RestoreTableFromInstanceParams p) { - btadmin::RestoreTableRequest proto; - proto.set_parent(instance_name); - proto.set_table_id(std::move(p.table_id)); - proto.set_backup(std::move(p.backup_name)); - return proto; -} - -StatusOr TableAdmin::RestoreTable( - RestoreTableFromInstanceParams params) { - google::cloud::internal::OptionsSpan span(options_); - auto request = AsProto(instance_name(), std::move(params)); - return connection_->RestoreTable(request).get(); -} - -StatusOr TableAdmin::ModifyColumnFamilies( - std::string const& table_id, - std::vector modifications) { - google::cloud::internal::OptionsSpan span(options_); - btadmin::ModifyColumnFamiliesRequest request; - request.set_name(TableName(table_id)); - for (auto& m : modifications) { - google::cloud::internal::OptionsSpan span(options_); - *request.add_modifications() = std::move(m).as_proto(); - } - return connection_->ModifyColumnFamilies(request); -} - -Status TableAdmin::DropRowsByPrefix(std::string const& table_id, - std::string row_key_prefix) { - google::cloud::internal::OptionsSpan span(options_); - btadmin::DropRowRangeRequest request; - request.set_name(TableName(table_id)); - request.set_row_key_prefix(std::move(row_key_prefix)); - return connection_->DropRowRange(request); -} - -future> TableAdmin::WaitForConsistency( - std::string const& table_id, std::string const& consistency_token) { - // We avoid lifetime issues due to ownership cycles, by holding the - // `BackgroundThreads` which run the `CompletionQueue` outside of the - // operation, in this class. If the `BackgroundThreads` running the - // `CompletionQueue` were instead owned by the Connection, we would have an - // ownership cycle. We have made this mistake before. See #7740 for more - // details. - auto client = bigtable_admin::BigtableTableAdminClient(connection_); - return bigtable_admin::AsyncWaitForConsistency(cq_, std::move(client), - TableName(table_id), - consistency_token, options_) - .then([](future f) -> StatusOr { - auto s = f.get(); - if (!s.ok()) return s; - return Consistency::kConsistent; - }); -} - -Status TableAdmin::DropAllRows(std::string const& table_id) { - google::cloud::internal::OptionsSpan span(options_); - btadmin::DropRowRangeRequest request; - request.set_name(TableName(table_id)); - request.set_delete_all_data_from_table(true); - return connection_->DropRowRange(request); -} - -StatusOr TableAdmin::GenerateConsistencyToken( - std::string const& table_id) { - google::cloud::internal::OptionsSpan span(options_); - btadmin::GenerateConsistencyTokenRequest request; - request.set_name(TableName(table_id)); - auto sor = connection_->GenerateConsistencyToken(request); - if (!sor) return std::move(sor).status(); - return std::move(*sor->mutable_consistency_token()); -} - -StatusOr TableAdmin::CheckConsistency( - std::string const& table_id, std::string const& consistency_token) { - google::cloud::internal::OptionsSpan span(options_); - btadmin::CheckConsistencyRequest request; - request.set_name(TableName(table_id)); - request.set_consistency_token(consistency_token); - auto sor = connection_->CheckConsistency(request); - if (!sor) return std::move(sor).status(); - return sor->consistent() ? Consistency::kConsistent - : Consistency::kInconsistent; -} - -StatusOr TableAdmin::GetIamPolicy( - std::string const& table_id) { - return GetIamPolicyImpl(TableName(table_id)); -} - -StatusOr TableAdmin::GetIamPolicy( - std::string const& cluster_id, std::string const& backup_id) { - return GetIamPolicyImpl(BackupName(cluster_id, backup_id)); -} - -StatusOr TableAdmin::GetIamPolicyImpl( - std::string resource) { - google::cloud::internal::OptionsSpan span(options_); - ::google::iam::v1::GetIamPolicyRequest request; - request.set_resource(std::move(resource)); - return connection_->GetIamPolicy(request); -} - -StatusOr TableAdmin::SetIamPolicy( - std::string const& table_id, google::iam::v1::Policy const& iam_policy) { - return SetIamPolicyImpl(TableName(table_id), iam_policy); -} - -StatusOr TableAdmin::SetIamPolicy( - std::string const& cluster_id, std::string const& backup_id, - google::iam::v1::Policy const& iam_policy) { - return SetIamPolicyImpl(BackupName(cluster_id, backup_id), iam_policy); -} - -StatusOr TableAdmin::SetIamPolicyImpl( - std::string resource, google::iam::v1::Policy const& iam_policy) { - google::cloud::internal::OptionsSpan span(options_); - ::google::iam::v1::SetIamPolicyRequest request; - request.set_resource(std::move(resource)); - *request.mutable_policy() = iam_policy; - return connection_->SetIamPolicy(request); -} - -StatusOr> TableAdmin::TestIamPermissions( - std::string const& table_id, std::vector const& permissions) { - return TestIamPermissionsImpl(TableName(table_id), permissions); -} - -StatusOr> TableAdmin::TestIamPermissions( - std::string const& cluster_id, std::string const& backup_id, - std::vector const& permissions) { - return TestIamPermissionsImpl(BackupName(cluster_id, backup_id), permissions); -} - -StatusOr> TableAdmin::TestIamPermissionsImpl( - std::string resource, std::vector const& permissions) { - google::cloud::internal::OptionsSpan span(options_); - ::google::iam::v1::TestIamPermissionsRequest request; - request.set_resource(std::move(resource)); - for (auto const& permission : permissions) { - request.add_permissions(permission); - } - auto sor = connection_->TestIamPermissions(request); - if (!sor) return std::move(sor).status(); - auto response = *std::move(sor); - std::vector result; - auto& ps = *response.mutable_permissions(); - std::move(ps.begin(), ps.end(), std::back_inserter(result)); - return result; -} - -std::string TableAdmin::InstanceName() const { - return google::cloud::bigtable::InstanceName(project_id_, instance_id_); -} - -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END -} // namespace bigtable -} // namespace cloud -} // namespace google diff --git a/google/cloud/bigtable/table_admin.h b/google/cloud/bigtable/table_admin.h deleted file mode 100644 index a53831d073b13..0000000000000 --- a/google/cloud/bigtable/table_admin.h +++ /dev/null @@ -1,1136 +0,0 @@ -// Copyright 2017 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 -// -// https://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. - -#ifndef GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_TABLE_ADMIN_H -#define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_TABLE_ADMIN_H - -#include "google/cloud/bigtable/admin/bigtable_table_admin_connection.h" -#include "google/cloud/bigtable/admin_client.h" -#include "google/cloud/bigtable/column_family.h" -#include "google/cloud/bigtable/completion_queue.h" -#include "google/cloud/bigtable/iam_policy.h" -#include "google/cloud/bigtable/internal/convert_policies.h" -#include "google/cloud/bigtable/polling_policy.h" -#include "google/cloud/bigtable/resource_names.h" -#include "google/cloud/bigtable/table_config.h" -#include "google/cloud/bigtable/version.h" -#include "google/cloud/future.h" -#include "google/cloud/grpc_error_delegate.h" -#include "google/cloud/options.h" -#include "google/cloud/status_or.h" -#include "absl/types/optional.h" -#include -#include -#include -#include -#include - -namespace google { -namespace cloud { -namespace bigtable_internal { -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN -class TableAdminTester; -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END -} // namespace bigtable_internal -namespace bigtable { -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN -/// The result of checking replication against a given token. -enum class Consistency { - /// Some of the mutations created before the consistency token have not been - /// received by all the table replicas. - kInconsistent, - /// All mutations created before the consistency token have been received by - /// all the table replicas. - kConsistent, -}; - -/** - * Implements the API to administer tables in a Cloud Bigtable instance. - * - * @par Thread-safety - * Instances of this class created via copy-construction or copy-assignment - * share the underlying pool of connections. Access to these copies via multiple - * threads is guaranteed to work. Two threads operating concurrently on the same - * instance of this class is not guaranteed to work. - * - * @par Cost - * Creating a new object of type `TableAdmin` is comparable to creating a few - * objects of type `std::string` or a few objects of type - * `std::shared_ptr`. The class represents a shallow handle to a remote - * object. - * - * @par Error Handling - * This class uses `StatusOr` to report errors. When an operation fails to - * perform its work the returned `StatusOr` contains the error details. If - * the `ok()` member function in the `StatusOr` returns `true` then it - * contains the expected result. Operations that do not return a value simply - * return a `google::cloud::Status` indicating success or the details of the - * error Please consult the [`StatusOr` - * documentation](#google::cloud::StatusOr) for more details. - * - * @code - * namespace cbt = google::cloud::bigtable; - * namespace btadmin = google::bigtable::admin::v2; - * cbt::TableAdmin admin = ...; - * google::cloud::StatusOr metadata = admin.GetTable(...); - * - * if (!metadata) { - * std::cerr << "Error fetching table metadata\n"; - * return; - * } - * - * // Use "metadata" as a smart pointer here, e.g.: - * std::cout << "The full table name is " << table->name() << " the table has " - * << table->column_families_size() << " column families\n"; - * @endcode - * - * In addition, the @ref index "main page" contains examples using `StatusOr` - * to handle errors. - * - * @par Retry, Backoff, and Idempotency Policies - * The library automatically retries requests that fail with transient errors, - * and uses [truncated exponential backoff][backoff-link] to backoff between - * retries. The default policies are to continue retrying for up to 10 minutes. - * On each transient failure the backoff period is doubled, starting with an - * initial backoff of 100 milliseconds. The backoff period growth is truncated - * at 60 seconds. The default idempotency policy is to only retry idempotent - * operations. Note that most operations that change state are **not** - * idempotent. - * - * The application can override these policies when constructing objects of this - * class. The documentation for the constructors show examples of this in - * action. - * - * [backoff-link]: https://cloud.google.com/storage/docs/exponential-backoff - * - * @par Equality - * `TableAdmin` objects will compare equal iff they were created with the - * same `DataClient` and target the same Instance resource. Note that - * `TableAdmin` objects can compare equal with different retry/backoff/polling - * policies. - * - * @see https://cloud.google.com/bigtable/ for an overview of Cloud Bigtable. - * - * @see https://cloud.google.com/bigtable/docs/overview for an overview of the - * Cloud Bigtable data model. - * - * @see https://cloud.google.com/bigtable/docs/instances-clusters-nodes for an - * introduction of the main APIs into Cloud Bigtable. - * - * @see https://cloud.google.com/bigtable/docs/reference/service-apis-overview - * for an overview of the underlying Cloud Bigtable API. - * - * @see #google::cloud::StatusOr for a description of the error reporting class - * used by this library. - * - * @see `LimitedTimeRetryPolicy` and `LimitedErrorCountRetryPolicy` for - * alternative retry policies. - * - * @see `ExponentialBackoffPolicy` to configure different parameters for the - * exponential backoff policy. - * - * @see `SafeIdempotentMutationPolicy` and `AlwaysRetryMutationPolicy` for - * alternative idempotency policies. - */ -class TableAdmin { - public: - /** - * @param client the interface to create grpc stubs, report errors, etc. - * @param instance_id the id of the instance, e.g., "my-instance", the full - * name (e.g. '/projects/my-project/instances/my-instance') is built using - * the project id in the @p client parameter. - */ - // NOLINTNEXTLINE(performance-unnecessary-value-param) - TableAdmin(std::shared_ptr client, std::string instance_id) - : connection_(client->connection_), - cq_(client->cq_), - background_threads_(client->background_threads_), - project_id_(client->project()), - instance_id_(std::move(instance_id)), - instance_name_(InstanceName()), - retry_prototype_( - DefaultRPCRetryPolicy(internal::kBigtableTableAdminLimits)), - backoff_prototype_( - DefaultRPCBackoffPolicy(internal::kBigtableTableAdminLimits)), - polling_prototype_( - DefaultPollingPolicy(internal::kBigtableTableAdminLimits)), - options_(google::cloud::internal::MergeOptions( - bigtable_internal::MakeTableAdminOptions( - retry_prototype_, backoff_prototype_, polling_prototype_), - connection_->options())) {} - - /** - * Create a new TableAdmin using explicit policies to handle RPC errors. - * - * @param client the interface to create grpc stubs, report errors, etc. - * @param instance_id the id of the instance, e.g., "my-instance", the full - * name (e.g. '/projects/my-project/instances/my-instance') is built using - * the project id in the @p client parameter. - * @param policies the set of policy overrides for this object. - * @tparam Policies the types of the policies to override, the types must - * derive from one of the following types: - * - `RPCBackoffPolicy` how to backoff from a failed RPC. Currently only - * `ExponentialBackoffPolicy` is implemented. You can also create your - * own policies that backoff using a different algorithm. - * - `RPCRetryPolicy` for how long to retry failed RPCs. Use - * `LimitedErrorCountRetryPolicy` to limit the number of failures - * allowed. Use `LimitedTimeRetryPolicy` to bound the time for any - * request. You can also create your own policies that combine time and - * error counts. - * - `PollingPolicy` for how long will the class wait for - * `google.longrunning.Operation` to complete. This class combines both - * the backoff policy for checking long running operations and the - * retry policy. - * - * @see GenericPollingPolicy, ExponentialBackoffPolicy, - * LimitedErrorCountRetryPolicy, LimitedTimeRetryPolicy. - */ - template - // NOLINTNEXTLINE(performance-unnecessary-value-param) - TableAdmin(std::shared_ptr client, std::string instance_id, - Policies&&... policies) - : connection_(client->connection_), - cq_(client->cq_), - background_threads_(client->background_threads_), - project_id_(client->project()), - instance_id_(std::move(instance_id)), - instance_name_(InstanceName()), - retry_prototype_( - DefaultRPCRetryPolicy(internal::kBigtableTableAdminLimits)), - backoff_prototype_( - DefaultRPCBackoffPolicy(internal::kBigtableTableAdminLimits)), - polling_prototype_( - DefaultPollingPolicy(internal::kBigtableTableAdminLimits)) { - ChangePolicies(std::forward(policies)...); - options_ = google::cloud::internal::MergeOptions( - bigtable_internal::MakeTableAdminOptions( - retry_prototype_, backoff_prototype_, polling_prototype_), - connection_->options()); - } - - TableAdmin(TableAdmin const&) = default; - TableAdmin& operator=(TableAdmin const&) = default; - - friend bool operator==(TableAdmin const& a, TableAdmin const& b) noexcept { - return a.connection_ == b.connection_ && - a.instance_name_ == b.instance_name_; - } - friend bool operator!=(TableAdmin const& a, TableAdmin const& b) noexcept { - return !(a == b); - } - - ///@{ - /// @name Convenience shorthands for the schema views. - using TableView = ::google::bigtable::admin::v2::Table::View; - /// Only populate 'name' and fields related to the table's encryption state. - static auto constexpr ENCRYPTION_VIEW = // NOLINT(readability-identifier-naming) - google::bigtable::admin::v2::Table::ENCRYPTION_VIEW; - /// Populate all the fields in the response. - static auto constexpr FULL = // NOLINT(readability-identifier-naming) - google::bigtable::admin::v2::Table::FULL; - /// Populate only the name in the responses. - static auto constexpr NAME_ONLY = // NOLINT(readability-identifier-naming) - google::bigtable::admin::v2::Table::NAME_ONLY; - /// Populate only the name and the fields related to the table replication - /// state. - static auto constexpr REPLICATION_VIEW = // NOLINT(readability-identifier-naming) - google::bigtable::admin::v2::Table::REPLICATION_VIEW; - /// Populate only the name and the fields related to the table schema. - static auto constexpr SCHEMA_VIEW = // NOLINT(readability-identifier-naming) - google::bigtable::admin::v2::Table::SCHEMA_VIEW; - /// Use the default view as defined for each function. - static auto constexpr VIEW_UNSPECIFIED = // NOLINT(readability-identifier-naming) - google::bigtable::admin::v2::Table::VIEW_UNSPECIFIED; - ///@} - - std::string const& project() const { return project_id_; } - std::string const& instance_id() const { return instance_id_; } - std::string const& instance_name() const { return instance_name_; } - - /** - * Returns a TableAdmin that reuses the connection and configuration of this - * TableAdmin, but with a different resource name. - */ - TableAdmin WithNewTarget(std::string project_id, - std::string instance_id) const { - auto table = *this; - table.project_id_ = std::move(project_id); - table.instance_id_ = std::move(instance_id); - table.instance_name_ = table.InstanceName(); - return table; - } - - /** - * Create a new table in the instance. - * - * @param table_id the name of the table relative to the instance managed by - * this object. The full table name is - * `projects//instances//tables/` - * where PROJECT_ID is obtained from the associated AdminClient and - * INSTANCE_ID is the instance_id() of this object. - * @param config the initial schema for the table. - * @return the attributes of the newly created table. Notice that the server - * only populates the table_name() field at this time. - * - * @par Idempotency - * This operation is always treated as non-idempotent. - * - * @par Thread-safety - * Two threads concurrently calling this member function on the same instance - * of this class are **not** guaranteed to work. Consider copying the object - * and using different copies in each thread. - * - * @par Example - * @snippet table_admin_snippets.cc create table - */ - StatusOr<::google::bigtable::admin::v2::Table> CreateTable( - std::string table_id, TableConfig config); - - /** - * Return all the tables in the instance. - * - * @param view define what information about the tables is retrieved. - * - `VIEW_UNSPECIFIED`: equivalent to `VIEW_SCHEMA`. - * - `NAME`: return only the name of the table. - * - `VIEW_SCHEMA`: return the name and the schema. - * - `FULL`: return all the information about the table. - * - * @par Idempotency - * This operation is read-only and therefore it is always idempotent. - * - * @par Thread-safety - * Two threads concurrently calling this member function on the same instance - * of this class are **not** guaranteed to work. Consider copying the object - * and using different copies in each thread. - * - * @par Example - * @snippet table_admin_snippets.cc list tables - */ - StatusOr> ListTables( - ::google::bigtable::admin::v2::Table::View view); - - /** - * Get information about a single table. - * - * @param table_id the id of the table within the instance associated with - * this object. The full name of the table is - * `this->instance_name() + "/tables/" + table_id` - * @param view describes how much information to get about the name. - * - VIEW_UNSPECIFIED: equivalent to VIEW_SCHEMA. - * - NAME: return only the name of the table. - * - VIEW_SCHEMA: return the name and the schema. - * - FULL: return all the information about the table. - * @return the information about the table or status. - * - * @par Idempotency - * This operation is read-only and therefore it is always idempotent. - * - * @par Thread-safety - * Two threads concurrently calling this member function on the same instance - * of this class are **not** guaranteed to work. Consider copying the object - * and using different copies in each thread. - * - * @par Example - * @snippet table_admin_snippets.cc get table - */ - StatusOr<::google::bigtable::admin::v2::Table> GetTable( - std::string const& table_id, TableView view = SCHEMA_VIEW); - - /** - * Delete a table. - * - * @param table_id the id of the table within the instance associated with - * this object. The full name of the table is - * `this->instance_name() + "/tables/" + table_id` - * - * @return status of the operation. - * - * @par Idempotency - * This operation is always treated as non-idempotent. - * - * @par Thread-safety - * Two threads concurrently calling this member function on the same instance - * of this class are **not** guaranteed to work. Consider copying the object - * and using different copies in each thread. - * - * @par Example - * @snippet table_admin_snippets.cc delete table - */ - Status DeleteTable(std::string const& table_id); - - /** - * Parameters for `CreateBackup`. - * - * @param cluster_id the name of the cluster relative to the instance managed - * by the `TableAdmin` object. The full cluster name is - * `projects//instances//clusters/` - * where PROJECT_ID is obtained from the associated AdminClient and - * INSTANCE_ID is the instance_id() of the `TableAdmin` object. - * @param backup_id the name of the backup relative to the cluster specified. - * The full backup name is - * `projects//instances//clusters//backups/` - * where PROJECT_ID is obtained from the associated AdminClient, - * INSTANCE_ID is the instance_id() of the `TableAdmin` object, and - * CLUSTER_ID is the cluster_id specified for this object. - * @param table_id the id of the table within the instance to be backed up. - * The full name of the table is - * `projects//instances//tables/` - * where PROJECT_ID is obtained from the associated AdminClient and - * INSTANCE_ID is the instance_id() of the `TableAdmin` object. - * @param expire_time the date and time when the created backup will expire. - */ - struct CreateBackupParams { - CreateBackupParams() = default; - CreateBackupParams(std::string cluster_id, std::string backup_id, - std::string table_id, - std::chrono::system_clock::time_point expire_time) - : cluster_id(std::move(cluster_id)), - backup_id(std::move(backup_id)), - table_name(std::move(table_id)), - expire_time(std::move(expire_time)) {} - - google::bigtable::admin::v2::CreateBackupRequest AsProto( - std::string instance_name) const; - - std::string cluster_id; - std::string backup_id; - std::string table_name; - std::chrono::system_clock::time_point expire_time; - }; - - /** - * Create a new backup of a table in the instance. - * - * @param params instance of `CreateBackupParams`. - * - * @par Idempotency - * This operation is always treated as non-idempotent. - * - * @par Thread-safety - * Two threads concurrently calling this member function on the same instance - * of this class are **not** guaranteed to work. Consider copying the object - * and using different copies in each thread. - * - * @par Example - * @snippet bigtable_table_admin_backup_snippets.cc create backup - */ - StatusOr CreateBackup( - CreateBackupParams const& params); - - /** - * Get information about a single backup. - * - * @param cluster_id the name of the cluster relative to the instance managed - * by the `TableAdmin` object. The full cluster name is - * `projects//instances//clusters/` - * where PROJECT_ID is obtained from the associated AdminClient and - * INSTANCE_ID is the instance_id() of the `TableAdmin` object. - * @param backup_id the name of the backup relative to the cluster specified. - * The full backup name is - * `projects//instances//clusters//backups/` - * where PROJECT_ID is obtained from the associated AdminClient, - * INSTANCE_ID is the instance_id() of the `TableAdmin` object, and - * CLUSTER_ID is the cluster_id previously specified. - * - * @par Idempotency - * This operation is read-only and therefore it is always idempotent. - * - * @par Thread-safety - * Two threads concurrently calling this member function on the same instance - * of this class are **not** guaranteed to work. Consider copying the object - * and using different copies in each thread. - * - * @par Example - * @snippet bigtable_table_admin_backup_snippets.cc get backup - */ - StatusOr GetBackup( - std::string const& cluster_id, std::string const& backup_id); - - /** - * Parameters for `UpdateBackup`. - * - * @param cluster_id the name of the cluster relative to the instance managed - * by the `TableAdmin` object. The full cluster name is - * `projects//instances//clusters/` - * where PROJECT_ID is obtained from the associated AdminClient and - * INSTANCE_ID is the instance_id() of the `TableAdmin` object. - * @param backup_id the name of the backup relative to the cluster specified. - * The full backup name is - * `projects//instances//clusters//backups/` - * where PROJECT_ID is obtained from the associated AdminClient, - * INSTANCE_ID is the instance_id() of the `TableAdmin` object, and - * CLUSTER_ID is the cluster_id specified for this object. - * @param expire_time the date and time when the created backup will expire. - */ - struct UpdateBackupParams { - UpdateBackupParams() = default; - UpdateBackupParams(std::string cluster_id, std::string backup_id, - std::chrono::system_clock::time_point expire_time) - : cluster_id(std::move(cluster_id)), - backup_name(std::move(backup_id)), - expire_time(std::move(expire_time)) {} - - google::bigtable::admin::v2::UpdateBackupRequest AsProto( - std::string const& instance_name) const; - - std::string cluster_id; - std::string backup_name; - std::chrono::system_clock::time_point expire_time; - }; - - /** - * Updates a backup of a table in the instance. - * - * @param params instance of `UpdateBackupParams`. - * - * @par Idempotency - * This operation is always treated as non-idempotent. - * - * @par Thread-safety - * Two threads concurrently calling this member function on the same instance - * of this class are **not** guaranteed to work. Consider copying the object - * and using different copies in each thread. - * - * @par Example - * @snippet bigtable_table_admin_backup_snippets.cc update backup - */ - StatusOr UpdateBackup( - UpdateBackupParams const& params); - - /** - * Delete a backup. - * - * @param cluster_id the name of the cluster relative to the instance managed - * by the `TableAdmin` object. The full cluster name is - * `projects//instances//clusters/` - * where PROJECT_ID is obtained from the associated AdminClient and - * INSTANCE_ID is the instance_id() of the `TableAdmin` object. - * @param backup_id the name of the backup relative to the cluster specified. - * The full backup name is - * `projects//instances//clusters//backups/` - * where PROJECT_ID is obtained from the associated AdminClient, - * INSTANCE_ID is the instance_id() of the `TableAdmin` object, and - * CLUSTER_ID is the cluster_id previously specified. - * - * @par Idempotency - * This operation is always treated as non-idempotent. - * - * @par Thread-safety - * Two threads concurrently calling this member function on the same instance - * of this class are **not** guaranteed to work. Consider copying the object - * and using different copies in each thread. - * - * @par Example - * @snippet bigtable_table_admin_backup_snippets.cc delete backup - */ - Status DeleteBackup(std::string const& cluster_id, - std::string const& backup_id); - - /** - * Delete a backup. - * - * @param backup typically returned by a call to `GetBackup` or `ListBackups`. - * - * @par Idempotency - * This operation is always treated as non-idempotent. - * - * @par Thread-safety - * Two threads concurrently calling this member function on the same instance - * of this class are **not** guaranteed to work. Consider copying the object - * and using different copies in each thread. - * - * @par Example - * @snippet bigtable_table_admin_backup_snippets.cc delete backup - */ - Status DeleteBackup(google::bigtable::admin::v2::Backup const& backup); - - /** - * Parameters for `ListBackups`. - */ - struct ListBackupsParams { - /** - * Sets the cluster_id. - * - * @param c the name of the cluster relative to the instance - * managed by the `TableAdmin` object. If no cluster_id is specified, - * the all backups in all clusters are listed. The full cluster name is - * `projects//instances//clusters/` - * where PROJECT_ID is obtained from the associated AdminClient and - * INSTANCE_ID is the instance_id() of the `TableAdmin` object. - */ - ListBackupsParams& set_cluster(std::string c) { - this->cluster_id = std::move(c); - return *this; - } - - /** - * Sets the filtering expression. - * - * @param f expression that filters backups listed in the response. - * The expression must specify the field name, a comparison operator, - * and the value that you want to use for filtering. The value must be a - * string, a number, or a boolean. The comparison operator must be - * <, >, <=, >=, !=, =, or :. Colon ‘:’ represents a HAS operator which - * is roughly synonymous with equality. Filter rules are case - * insensitive. - * - * The fields eligible for filtering are: - * * `name` - * * `table` - * * `state` - * * `start_time` (and values are of the format - * `YYYY-MM-DDTHH:MM:SSZ`) - * * `end_time` (and values are of the format `YYYY-MM-DDTHH:MM:SSZ`) - * * `expire_time` (and values are of the format - * `YYYY-MM-DDTHH:MM:SSZ`) - * * `size_bytes` - * - * To filter on multiple expressions, provide each separate expression - * within parentheses. By default, each expression is an AND expression. - * However, you can include AND, OR, and NOT expressions explicitly. - * - * Some examples of using filters are: - * * `name:"exact"` --> The backup's name is the string "exact". - * * `name:howl` --> The backup's name contains the string "howl". - * * `table:prod` --> The table's name contains the string "prod". - * * `state:CREATING` --> The backup is pending creation. - * * `state:READY` --> The backup is fully created and ready for use. - * * `(name:howl) AND (start_time < "2018-03-28T14:50:00Z")` - * --> The backup name contains the string "howl" and start_time - * of the backup is before `2018-03-28T14:50:00Z`. - * * `size_bytes > 10000000000` --> The backup's size is greater than - * 10GB - */ - ListBackupsParams& set_filter(std::string f) { - this->filter = std::move(f); - return *this; - } - - /** - * Sets the ordering expression. - * - * @param o expression for specifying the sort order of the results - * of the request. The string value should specify only one field in - * `google::bigtable::admin::v2::Backup`. - * The following field names are supported: - * * name - * * table - * * expire_time - * * start_time - * * end_time - * * size_bytes - * * state - * - * For example, "start_time". The default sorting order is ascending. - * Append the " desc" suffix to the field name to sort descending, e.g. - * "start_time desc". Redundant space characters in the syntax are - * insignificant. - * - * If order_by is empty, results will be sorted by `start_time` in - * descending order starting from the most recently created backup. - */ - ListBackupsParams& set_order_by(std::string o) { - this->order_by = std::move(o); - return *this; - } - - google::bigtable::admin::v2::ListBackupsRequest AsProto( - std::string const& instance_name) const; - - absl::optional cluster_id; - absl::optional filter; - absl::optional order_by; - }; - - /** - * Retrieves a list of backups. - * - * @param params instance of `ListBackupsParams`. - * - * @par Idempotency - * This operation is read-only and therefore it is always idempotent. - * - * @par Thread-safety - * Two threads concurrently calling this member function on the same instance - * of this class are **not** guaranteed to work. Consider copying the object - * and using different copies in each thread. - * - * @par Example - * @snippet bigtable_table_admin_backup_snippets.cc list backups - */ - StatusOr> ListBackups( - ListBackupsParams const& params); - - /** - * Parameters for `RestoreTable`. - * - * @param table_id the name of the table relative to the instance managed by - * this object. The full table name is - * `projects//instances//tables/` - * where PROJECT_ID is obtained from the associated AdminClient and - * INSTANCE_ID is the instance_id() of this object. - * @param cluster_id the name of the cluster relative to the instance managed - * by the `TableAdmin` object. The full cluster name is - * `projects//instances//clusters/` - * where PROJECT_ID is obtained from the associated AdminClient and - * INSTANCE_ID is the instance_id() of the `TableAdmin` object. - * @param backup_id the name of the backup relative to the cluster specified. - * The full backup name is - * `projects//instances//clusters//backups/` - * where PROJECT_ID is obtained from the associated AdminClient, - * INSTANCE_ID is the instance_id() of the `TableAdmin` object, and - * CLUSTER_ID is the cluster_id previously specified. - */ - struct RestoreTableParams { - RestoreTableParams() = default; - RestoreTableParams(std::string table_id, std::string cluster_id, - std::string backup_id) - : table_id(std::move(table_id)), - cluster_id(std::move(cluster_id)), - backup_id(std::move(backup_id)) {} - - /// @deprecated covert the parameters to a proto. - google::bigtable::admin::v2::RestoreTableRequest AsProto( - std::string const& instance_name) const; - - std::string table_id; - std::string cluster_id; - std::string backup_id; - }; - - /** - * Parameters for `RestoreTable`. - * - * @param table_id the name of the table relative to the instance managed by - * this object. The full table name is - * `projects//instances//tables/` - * where PROJECT_ID is obtained from the associated AdminClient and - * INSTANCE_ID is the instance_id() of this object. - * @param backup_name the full name of the backup used to restore @p table_id. - */ - struct RestoreTableFromInstanceParams { - std::string table_id; - std::string backup_name; - }; - - /** - * Restore a backup into a new table in the instance. - * - * @param params instance of `RestoreTableParams`. - * - * @par Idempotency - * This operation is always treated as non-idempotent. - * - * @par Thread-safety - * Two threads concurrently calling this member function on the same instance - * of this class are **not** guaranteed to work. Consider copying the object - * and using different copies in each thread. - * - * @par Example - * @snippet bigtable_table_admin_backup_snippets.cc restore table - */ - StatusOr RestoreTable( - RestoreTableParams const& params); - - /** - * Restore a backup into a new table in the instance. - * - * @param params instance of `RestoreTableFromInstanceParams`. - * - * @par Idempotency - * This operation is always treated as non-idempotent. - * - * @par Thread-safety - * Two threads concurrently calling this member function on the same instance - * of this class are **not** guaranteed to work. Consider copying the object - * and using different copies in each thread. - * - * @par Example - * @snippet bigtable_table_admin_backup_snippets.cc restore2 - */ - StatusOr RestoreTable( - RestoreTableFromInstanceParams params); - - /** - * Modify the schema for an existing table. - * - * @param table_id the id of the table within the instance associated with - * this object. The full name of the table is - * `this->instance_name() + "/tables/" + table_id` - * @param modifications the list of modifications to the schema. - * - * @par Idempotency - * This operation is always treated as non-idempotent. - * - * @par Thread-safety - * Two threads concurrently calling this member function on the same instance - * of this class are **not** guaranteed to work. Consider copying the object - * and using different copies in each thread. - * - * @par Example - * @snippet table_admin_snippets.cc modify table - */ - StatusOr<::google::bigtable::admin::v2::Table> ModifyColumnFamilies( - std::string const& table_id, - std::vector modifications); - - /** - * Delete all the rows that start with a given prefix. - * - * @param table_id the id of the table within the instance associated with - * this object. The full name of the table is - * `this->instance_name() + "/tables/" + table_id` - * @param row_key_prefix drop any rows that start with this prefix. - * - * @par Idempotency - * This operation is always treated as non-idempotent. - * - * @par Thread-safety - * Two threads concurrently calling this member function on the same instance - * of this class are **not** guaranteed to work. Consider copying the object - * and using different copies in each thread. - * - * @par Example - * @snippet table_admin_snippets.cc drop rows by prefix - */ - Status DropRowsByPrefix(std::string const& table_id, - std::string row_key_prefix); - - /** - * Generates consistency token for a table. - * - * @param table_id the id of the table for which we want to generate - * consistency token. - * @return the consistency token for table. - * - * @par Idempotency - * This operation is read-only and therefore it is always idempotent. - * - * @par Thread-safety - * Two threads concurrently calling this member function on the same instance - * of this class are **not** guaranteed to work. Consider copying the object - * and using different copies in each thread. - * - * @par Example - * @snippet table_admin_snippets.cc generate consistency token - */ - StatusOr GenerateConsistencyToken(std::string const& table_id); - - /** - * Checks consistency of a table. - * - * @param table_id the id of the table for which we want to check - * consistency. - * @param consistency_token the consistency token of the table. - * @return the consistency status for the table. - * - * @par Idempotency - * This operation is read-only and therefore it is always idempotent. - * - * @par Thread-safety - * Two threads concurrently calling this member function on the same instance - * of this class are **not** guaranteed to work. Consider copying the object - * and using different copies in each thread. - * - * @par Example - * @snippet table_admin_snippets.cc check consistency - */ - StatusOr CheckConsistency(std::string const& table_id, - std::string const& consistency_token); - - /** - * Checks consistency of a table with multiple calls using a separate thread - * - * @param table_id the id of the table for which we want to check - * consistency. - * @param consistency_token the consistency token of the table. - * @return the consistency status for the table. - * - * @par Idempotency - * This operation is read-only and therefore it is always idempotent. - * - * @par Thread-safety - * Two threads concurrently calling this member function on the same instance - * of this class are **not** guaranteed to work. Consider copying the object - * and using different copies in each thread. - * - * @par Example - * @snippet table_admin_snippets.cc wait for consistency check - */ - google::cloud::future> WaitForConsistency( - std::string const& table_id, std::string const& consistency_token); - - /** - * Delete all the rows in a table. - * - * @param table_id the id of the table within the instance associated with - * this object. The full name of the table is - * `this->instance_name() + "/tables/" + table_id` - * - * @par Idempotency - * This operation is always treated as non-idempotent. - * - * @par Thread-safety - * Two threads concurrently calling this member function on the same instance - * of this class are **not** guaranteed to work. Consider copying the object - * and using different copies in each thread. - * - * @par Example - * @snippet table_admin_snippets.cc drop all rows - */ - Status DropAllRows(std::string const& table_id); - - /** - * Gets the policy for @p table_id. - * - * @param table_id the table to query. - * @return google::iam::v1::Policy the full IAM policy for the table. - * - * @par Idempotency - * This operation is read-only and therefore it is always idempotent. - * - * @par Thread-safety - * Two threads concurrently calling this member function on the same instance - * of this class are **not** guaranteed to work. Consider copying the object - * and using different copies in each thread. - * - * @par Example - * @snippet table_admin_iam_policy_snippets.cc get iam policy - */ - StatusOr GetIamPolicy(std::string const& table_id); - - /** - * Gets the policy for @p backup_id. - * - * @param cluster_id the associated cluster that contains backup. - * - * @param backup_id the backup to query. - * @return google::iam::v1::Policy the full IAM policy for the backup. - * - * @par Idempotency - * This operation is read-only and therefore it is always idempotent. - * - * @par Thread-safety - * Two threads concurrently calling this member function on the same instance - * of this class are **not** guaranteed to work. Consider copying the object - * and using different copies in each thread. - * - * @par Example - * @snippet bigtable_table_admin_backup_snippets.cc get backup iam policy - */ - StatusOr GetIamPolicy(std::string const& cluster_id, - std::string const& backup_id); - - /** - * Sets the IAM policy for a table. - * - * This is the preferred way to overload `IamBindings`. This is more closely - * coupled to the underlying protocol, enable more actions and is more likely - * to tolerate future protocol changes. - * - * @param table_id which table to set the IAM policy for. - * @param iam_policy google::iam::v1::Policy object containing role and - * members. - * @return google::iam::v1::Policy the current IAM policy for the table. - * - * @warning ETags are currently not used by Cloud Bigtable. - * - * @par Idempotency - * This operation is always treated as non-idempotent. - * - * @par Thread-safety - * Two threads concurrently calling this member function on the same instance - * of this class are **not** guaranteed to work. Consider copying the object - * and using different copies in each thread. - * - * @par Example - * @snippet table_admin_iam_policy_snippets.cc set iam policy - */ - StatusOr SetIamPolicy( - std::string const& table_id, google::iam::v1::Policy const& iam_policy); - - /** - * Sets the IAM policy for a backup. - * - * This is the preferred way to overload `IamBindings`. This is more closely - * coupled to the underlying protocol, enable more actions and is more likely - * to tolerate future protocol changes. - * - * @param cluster_id which is the cluster containing the backup. - * @param backup_id which backup to set the IAM policy for. - * @param iam_policy google::iam::v1::Policy object containing role and - * members. - * @return google::iam::v1::Policy the current IAM policy for the table. - * - * @warning ETags are currently not used by Cloud Bigtable. - * - * @par Idempotency - * This operation is always treated as non-idempotent. - * - * @par Thread-safety - * Two threads concurrently calling this member function on the same instance - * of this class are **not** guaranteed to work. Consider copying the object - * and using different copies in each thread. - * - * @par Example - * @snippet bigtable_table_admin_backup_snippets.cc set backup iam policy - */ - StatusOr SetIamPolicy( - std::string const& cluster_id, std::string const& backup_id, - google::iam::v1::Policy const& iam_policy); - - /** - * Returns a permission set that the caller has on the specified table. - * - * @param table_id the ID of the table to query. - * @param permissions set of permissions to check for the resource. - * - * @par Idempotency - * This operation is read-only and therefore it is always idempotent. - * - * @par Thread-safety - * Two threads concurrently calling this member function on the same instance - * of this class are **not** guaranteed to work. Consider copying the object - * and using different copies in each thread. - * - * @par Example - * @snippet table_admin_iam_policy_snippets.cc test iam permissions - * - * @see https://cloud.google.com/bigtable/docs/access-control for a list of - * valid permissions on Google Cloud Bigtable. - */ - StatusOr> TestIamPermissions( - std::string const& table_id, std::vector const& permissions); - - /** - * Returns a permission set that the caller has on the specified backup. - * - * @param cluster_id the ID of the cluster that contains the backup. - * @param backup_id the ID of the backup to query. - * @param permissions set of permissions to check for the resource. - * - * @par Idempotency - * This operation is read-only and therefore it is always idempotent. - * - * @par Thread-safety - * Two threads concurrently calling this member function on the same instance - * of this class are **not** guaranteed to work. Consider copying the object - * and using different copies in each thread. - * - * @par Example - * @snippet table_admin_iam_policy_snippets.cc test iam permissions - * - * @see https://cloud.google.com/bigtable/docs/access-control for a list of - * valid permissions on Google Cloud Bigtable. - */ - StatusOr> TestIamPermissions( - std::string const& cluster_id, std::string const& backup_id, - std::vector const& permissions); - - /// Return the fully qualified name of a table in this object's instance. - std::string TableName(std::string const& table_id) const { - return google::cloud::bigtable::TableName(project_id_, instance_id_, - table_id); - } - - /// Return the fully qualified name of a Cluster. - std::string ClusterName(std::string const& cluster_id) const { - return google::cloud::bigtable::ClusterName(project_id_, instance_id_, - cluster_id); - } - - /// Return the fully qualified name of a Backup. - std::string BackupName(std::string const& cluster_id, - std::string const& backup_id) const { - return google::cloud::bigtable::BackupName(project_id_, instance_id_, - cluster_id, backup_id); - } - - private: - friend class bigtable_internal::TableAdminTester; - - explicit TableAdmin( - std::shared_ptr connection, - CompletionQueue cq, std::string project_id, std::string instance_id) - : connection_(std::move(connection)), - cq_(std::move(cq)), - project_id_(std::move(project_id)), - instance_id_(std::move(instance_id)), - instance_name_(InstanceName()), - retry_prototype_( - DefaultRPCRetryPolicy(internal::kBigtableTableAdminLimits)), - backoff_prototype_( - DefaultRPCBackoffPolicy(internal::kBigtableTableAdminLimits)), - polling_prototype_( - DefaultPollingPolicy(internal::kBigtableTableAdminLimits)), - options_(google::cloud::internal::MergeOptions( - bigtable_internal::MakeTableAdminOptions( - retry_prototype_, backoff_prototype_, polling_prototype_), - connection_->options())) {} - - ///@{ - /// @name Helper functions to implement constructors with changed policies. - void ChangePolicy(RPCRetryPolicy const& policy) { - retry_prototype_ = policy.clone(); - } - - void ChangePolicy(RPCBackoffPolicy const& policy) { - backoff_prototype_ = policy.clone(); - } - - void ChangePolicy(PollingPolicy const& policy) { - polling_prototype_ = policy.clone(); - } - - template - void ChangePolicies(Policy&& policy, Policies&&... policies) { - ChangePolicy(policy); - ChangePolicies(std::forward(policies)...); - } - void ChangePolicies() {} - ///@} - - /// Compute the fully qualified instance name. - std::string InstanceName() const; - - StatusOr GetIamPolicyImpl(std::string resource); - - StatusOr SetIamPolicyImpl( - std::string resource, google::iam::v1::Policy const& iam_policy); - - StatusOr> TestIamPermissionsImpl( - std::string resource, std::vector const& permissions); - - std::shared_ptr connection_; - CompletionQueue cq_; - std::shared_ptr background_threads_; - std::string project_id_; - std::string instance_id_; - std::string instance_name_; - ///@{ - /// These prototypes are only used as temporary storage during construction of - /// the class, where they are consolidated as common policies in `options_`. - std::shared_ptr retry_prototype_; - std::shared_ptr backoff_prototype_; - std::shared_ptr polling_prototype_; - ///@} - Options options_; -}; - -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END -} // namespace bigtable -} // namespace cloud -} // namespace google - -#endif // GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_TABLE_ADMIN_H diff --git a/google/cloud/bigtable/table_admin_test.cc b/google/cloud/bigtable/table_admin_test.cc deleted file mode 100644 index b27134b6a102c..0000000000000 --- a/google/cloud/bigtable/table_admin_test.cc +++ /dev/null @@ -1,950 +0,0 @@ -// Copyright 2022 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 -// -// https://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. - -#include "google/cloud/bigtable/table_admin.h" -#include "google/cloud/bigtable/admin/bigtable_table_admin_connection.h" -#include "google/cloud/bigtable/admin/bigtable_table_admin_options.h" -#include "google/cloud/bigtable/admin/mocks/mock_bigtable_table_admin_connection.h" -#include "google/cloud/bigtable/testing/mock_policies.h" -#include "google/cloud/internal/background_threads_impl.h" -#include "google/cloud/internal/time_utils.h" -#include "google/cloud/testing_util/is_proto_equal.h" -#include "google/cloud/testing_util/status_matchers.h" -#include -#include -#include -#include - -namespace google { -namespace cloud { -namespace bigtable_internal { -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN - -// Helper class for checking that the legacy API still functions correctly -class TableAdminTester { - public: - static bigtable::TableAdmin MakeTestTableAdmin( - std::shared_ptr conn, - CompletionQueue cq, std::string const& kProjectId, - std::string const& kInstanceId) { - return bigtable::TableAdmin(std::move(conn), std::move(cq), kProjectId, - kInstanceId); - } - - static std::shared_ptr - Connection(bigtable::TableAdmin const& admin) { - return admin.connection_; - } - - static CompletionQueue CQ(bigtable::TableAdmin const& admin) { - return admin.cq_; - } - - static std::shared_ptr Threads( - bigtable::TableAdmin const& admin) { - return admin.background_threads_; - } - - static ::google::cloud::Options Options(bigtable::TableAdmin const& admin) { - return admin.options_; - } -}; - -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END -} // namespace bigtable_internal -namespace bigtable { -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN - -namespace { - -namespace btadmin = ::google::bigtable::admin::v2; -namespace iamproto = ::google::iam::v1; - -using ::google::cloud::bigtable::testing::MockBackoffPolicy; -using ::google::cloud::bigtable::testing::MockPollingPolicy; -using ::google::cloud::bigtable::testing::MockRetryPolicy; -using ::google::cloud::bigtable_internal::TableAdminTester; -using ::google::cloud::internal::ToChronoTimePoint; -using ::google::cloud::testing_util::IsProtoEqual; -using ::google::cloud::testing_util::StatusIs; -using std::chrono::hours; -using ::testing::An; -using ::testing::ElementsAre; -using ::testing::ElementsAreArray; -using ::testing::IsNull; -using ::testing::NotNull; -using ::testing::Return; -using ::testing::UnorderedElementsAreArray; -using MockConnection = - ::google::cloud::bigtable_admin_mocks::MockBigtableTableAdminConnection; - -auto const* const kProjectId = "the-project"; -auto const* const kInstanceId = "the-instance"; -auto const* const kTableId = "the-table"; -auto const* const kClusterId = "the-cluster"; -auto const* const kBackupId = "the-backup"; -auto const* const kInstanceName = "projects/the-project/instances/the-instance"; -auto const* const kTableName = - "projects/the-project/instances/the-instance/tables/the-table"; -auto const* const kClusterName = - "projects/the-project/instances/the-instance/clusters/the-cluster"; -auto const* const kBackupName = - "projects/the-project/instances/the-instance/clusters/the-cluster/backups/" - "the-backup"; - -struct TestOption { - using Type = int; -}; - -Options TestOptions() { - return Options{} - .set(grpc::InsecureChannelCredentials()) - .set(1); -} - -Status FailingStatus() { return Status(StatusCode::kPermissionDenied, "fail"); } - -bool SameCQ(CompletionQueue const& a, CompletionQueue const& b) { - using ::google::cloud::internal::GetCompletionQueueImpl; - return GetCompletionQueueImpl(a) == GetCompletionQueueImpl(b); -} - -void CheckOptions(Options const& options) { - EXPECT_TRUE( - options.has()); - EXPECT_TRUE( - options.has()); - EXPECT_TRUE( - options.has()); - EXPECT_TRUE(options.has()); - EXPECT_TRUE(options.has()); - EXPECT_TRUE(options.has()); -} - -class TableAdminTest : public ::testing::Test { - protected: - TableAdmin DefaultTableAdmin() { - EXPECT_CALL(*connection_, options()) - .WillRepeatedly(Return(Options{}.set(1))); - return TableAdminTester::MakeTestTableAdmin(connection_, {}, kProjectId, - kInstanceId); - } - - std::shared_ptr connection_ = - std::make_shared(); -}; - -TEST_F(TableAdminTest, Equality) { - auto client1 = MakeAdminClient(kProjectId, TestOptions()); - auto client2 = MakeAdminClient(kProjectId, TestOptions()); - auto ta1 = TableAdmin(client1, "i1"); - auto ta2 = TableAdmin(client1, "i2"); - auto ta3 = TableAdmin(client2, "i1"); - EXPECT_NE(ta1, ta2); - EXPECT_NE(ta1, ta3); - EXPECT_NE(ta2, ta3); - - ta2 = ta1; - EXPECT_EQ(ta1, ta2); -} - -TEST_F(TableAdminTest, ResourceNames) { - auto admin = DefaultTableAdmin(); - EXPECT_EQ(kProjectId, admin.project()); - EXPECT_EQ(kInstanceId, admin.instance_id()); - EXPECT_EQ(kInstanceName, admin.instance_name()); -} - -TEST_F(TableAdminTest, WithNewTarget) { - auto admin = DefaultTableAdmin(); - auto other_admin = admin.WithNewTarget("other-project", "other-instance"); - EXPECT_EQ(other_admin.project(), "other-project"); - EXPECT_EQ(other_admin.instance_id(), "other-instance"); - EXPECT_EQ(other_admin.instance_name(), - InstanceName("other-project", "other-instance")); -} - -TEST_F(TableAdminTest, LegacyConstructorSharesConnection) { - auto admin_client = MakeAdminClient(kProjectId, TestOptions()); - auto admin_1 = TableAdmin(admin_client, kInstanceId); - auto admin_2 = TableAdmin(admin_client, kInstanceId); - auto conn_1 = TableAdminTester::Connection(admin_1); - auto conn_2 = TableAdminTester::Connection(admin_2); - - EXPECT_EQ(conn_1, conn_2); - EXPECT_THAT(conn_1, NotNull()); -} - -TEST_F(TableAdminTest, LegacyConstructorSetsCQ) { - auto admin_client = MakeAdminClient(kProjectId, TestOptions()); - auto admin = TableAdmin(admin_client, kInstanceId); - auto conn = TableAdminTester::Connection(admin); - ASSERT_TRUE(conn->options().has()); - auto conn_cq = conn->options().get(); - auto client_cq = TableAdminTester::CQ(admin); - - EXPECT_TRUE(SameCQ(conn_cq, client_cq)); - EXPECT_THAT(TableAdminTester::Threads(admin), NotNull()); -} - -TEST_F(TableAdminTest, LegacyConstructorSetsCustomCQ) { - CompletionQueue user_cq; - auto admin_client = MakeAdminClient( - kProjectId, TestOptions().set(user_cq)); - auto admin = TableAdmin(admin_client, kInstanceId); - auto conn = TableAdminTester::Connection(admin); - ASSERT_TRUE(conn->options().has()); - auto conn_cq = conn->options().get(); - auto client_cq = TableAdminTester::CQ(admin); - - EXPECT_TRUE(SameCQ(user_cq, client_cq)); - EXPECT_TRUE(SameCQ(conn_cq, client_cq)); - EXPECT_THAT(TableAdminTester::Threads(admin), IsNull()); -} - -TEST_F(TableAdminTest, LegacyConstructorDefaultsPolicies) { - auto admin_client = MakeAdminClient(kProjectId, TestOptions()); - auto admin = TableAdmin(std::move(admin_client), kInstanceId); - auto options = TableAdminTester::Options(admin); - CheckOptions(options); -} - -TEST_F(TableAdminTest, LegacyConstructorWithPolicies) { - // In this test, we make a series of simple calls to verify that the policies - // passed to the `TableAdmin` constructor are actually collected as - // `Options`. - // - // Upon construction of an TableAdmin, each policy is cloned twice: Once - // while processing the variadic parameters, once while converting from - // Bigtable policies to common policies. This should explain the nested mocks - // below. - - auto mock_r = std::make_shared(); - auto mock_b = std::make_shared(); - auto mock_p = std::make_shared(); - - EXPECT_CALL(*mock_r, clone).WillOnce([] { - auto clone_1 = std::make_unique(); - EXPECT_CALL(*clone_1, clone).WillOnce([] { - auto clone_2 = std::make_unique(); - EXPECT_CALL(*clone_2, OnFailure(An())); - return clone_2; - }); - return clone_1; - }); - - EXPECT_CALL(*mock_b, clone).WillOnce([] { - auto clone_1 = std::make_unique(); - EXPECT_CALL(*clone_1, clone).WillOnce([] { - auto clone_2 = std::make_unique(); - EXPECT_CALL(*clone_2, OnCompletion(An())); - return clone_2; - }); - return clone_1; - }); - - EXPECT_CALL(*mock_p, clone).WillOnce([] { - auto clone_1 = std::make_unique(); - EXPECT_CALL(*clone_1, clone).WillOnce([] { - auto clone_2 = std::make_unique(); - EXPECT_CALL(*clone_2, WaitPeriod); - return clone_2; - }); - return clone_1; - }); - - auto admin_client = MakeAdminClient(kProjectId, TestOptions()); - auto admin = TableAdmin(std::move(admin_client), kInstanceId, *mock_r, - *mock_b, *mock_p); - auto options = TableAdminTester::Options(admin); - CheckOptions(options); - - auto const& common_retry = - options.get(); - (void)common_retry->OnFailure({}); - - auto const& common_backoff = - options.get(); - (void)common_backoff->OnCompletion(); - - auto const& common_polling = - options.get(); - (void)common_polling->WaitPeriod(); -} - -TEST_F(TableAdminTest, CreateTable) { - auto admin = DefaultTableAdmin(); - std::string expected_request = R"pb( - parent: 'projects/the-project/instances/the-instance' - table_id: 'the-table' - table { - column_families { - key: 'f1' - value { gc_rule { max_num_versions: 1 } } - } - column_families { - key: 'f2' - value { gc_rule { max_age { seconds: 1 } } } - } - granularity: TIMESTAMP_GRANULARITY_UNSPECIFIED - } - initial_splits { key: 'a' } - initial_splits { key: 'c' } - initial_splits { key: 'p' } - )pb"; - - EXPECT_CALL(*connection_, CreateTable) - .WillOnce( - [&expected_request](btadmin::CreateTableRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - btadmin::CreateTableRequest expected; - EXPECT_TRUE(google::protobuf::TextFormat::ParseFromString( - expected_request, &expected)); - EXPECT_THAT(expected, IsProtoEqual(request)); - return FailingStatus(); - }); - - TableConfig config({{"f1", GcRule::MaxNumVersions(1)}, - {"f2", GcRule::MaxAge(std::chrono::seconds(1))}}, - {"a", "c", "p"}); - EXPECT_THAT(admin.CreateTable(kTableId, config), - StatusIs(StatusCode::kPermissionDenied)); -} - -TEST_F(TableAdminTest, ListTablesSuccess) { - auto admin = DefaultTableAdmin(); - auto const expected_view = btadmin::Table::FULL; - std::vector const expected_names = { - TableName(kProjectId, kInstanceId, "t0"), - TableName(kProjectId, kInstanceId, "t1")}; - - auto iter = expected_names.begin(); - EXPECT_CALL(*connection_, ListTables) - .WillOnce([&iter, &expected_names, - expected_view](btadmin::ListTablesRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - EXPECT_EQ(kInstanceName, request.parent()); - EXPECT_EQ(expected_view, request.view()); - - using ::google::cloud::internal::MakeStreamRange; - using ::google::cloud::internal::StreamReader; - auto reader = - [&iter, - &expected_names]() -> StreamReader::result_type { - if (iter != expected_names.end()) { - btadmin::Table t; - t.set_name(*iter); - ++iter; - return t; - } - return Status(); - }; - return MakeStreamRange(std::move(reader)); - }); - - auto tables = admin.ListTables(expected_view); - ASSERT_STATUS_OK(tables); - std::vector names; - std::transform(tables->begin(), tables->end(), std::back_inserter(names), - [](btadmin::Table const& t) { return t.name(); }); - - EXPECT_THAT(names, ElementsAreArray(expected_names)); -} - -TEST_F(TableAdminTest, ListTablesFailure) { - auto admin = DefaultTableAdmin(); - auto const expected_view = btadmin::Table::NAME_ONLY; - - EXPECT_CALL(*connection_, ListTables) - .WillOnce([&expected_view](btadmin::ListTablesRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - EXPECT_EQ(kInstanceName, request.parent()); - EXPECT_EQ(expected_view, request.view()); - - using ::google::cloud::internal::MakeStreamRange; - return MakeStreamRange([] { return FailingStatus(); }); - }); - - EXPECT_THAT(admin.ListTables(expected_view), - StatusIs(StatusCode::kPermissionDenied)); -} - -TEST_F(TableAdminTest, GetTable) { - auto admin = DefaultTableAdmin(); - auto const expected_view = btadmin::Table::NAME_ONLY; - - EXPECT_CALL(*connection_, GetTable) - .WillOnce([&expected_view](btadmin::GetTableRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - EXPECT_EQ(kTableName, request.name()); - EXPECT_EQ(expected_view, request.view()); - return FailingStatus(); - }); - - EXPECT_THAT(admin.GetTable(kTableId, expected_view), - StatusIs(StatusCode::kPermissionDenied)); -} - -TEST_F(TableAdminTest, DeleteTable) { - auto admin = DefaultTableAdmin(); - - EXPECT_CALL(*connection_, DeleteTable) - .WillOnce([](btadmin::DeleteTableRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - EXPECT_EQ(kTableName, request.name()); - return FailingStatus(); - }); - - EXPECT_THAT(admin.DeleteTable(kTableId), - StatusIs(StatusCode::kPermissionDenied)); -} - -TEST_F(TableAdminTest, CreateBackupParams) { - auto const expire_time = std::chrono::system_clock::now() + hours(24); - TableAdmin::CreateBackupParams params(kClusterId, kBackupId, kTableId, - expire_time); - - auto request = params.AsProto(kInstanceName); - EXPECT_EQ(kClusterName, request.parent()); - EXPECT_EQ(kBackupId, request.backup_id()); - EXPECT_EQ(kTableName, request.backup().source_table()); - EXPECT_EQ(expire_time, ToChronoTimePoint(request.backup().expire_time())); -} - -TEST_F(TableAdminTest, CreateBackup) { - auto const expire_time = std::chrono::system_clock::now() + hours(24); - auto admin = DefaultTableAdmin(); - - EXPECT_CALL(*connection_, - CreateBackup(An())) - .WillOnce([expire_time](btadmin::CreateBackupRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - EXPECT_EQ(kClusterName, request.parent()); - EXPECT_EQ(kBackupId, request.backup_id()); - EXPECT_EQ(kTableName, request.backup().source_table()); - EXPECT_EQ(expire_time, - ToChronoTimePoint(request.backup().expire_time())); - return make_ready_future>(FailingStatus()); - }); - - TableAdmin::CreateBackupParams params(kClusterId, kBackupId, kTableId, - expire_time); - EXPECT_THAT(admin.CreateBackup(params), - StatusIs(StatusCode::kPermissionDenied)); -} - -TEST_F(TableAdminTest, GetBackup) { - auto admin = DefaultTableAdmin(); - - EXPECT_CALL(*connection_, GetBackup) - .WillOnce([](btadmin::GetBackupRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - EXPECT_EQ(kBackupName, request.name()); - return FailingStatus(); - }); - - EXPECT_THAT(admin.GetBackup(kClusterId, kBackupId), - StatusIs(StatusCode::kPermissionDenied)); -} - -TEST_F(TableAdminTest, UpdateBackupParams) { - auto const expire_time = std::chrono::system_clock::now() + hours(24); - TableAdmin::UpdateBackupParams params(kClusterId, kBackupId, expire_time); - - auto request = params.AsProto(kInstanceName); - EXPECT_EQ(kBackupName, request.backup().name()); - EXPECT_EQ(expire_time, ToChronoTimePoint(request.backup().expire_time())); - EXPECT_THAT(request.update_mask().paths(), ElementsAre("expire_time")); -} - -TEST_F(TableAdminTest, UpdateBackup) { - auto const expire_time = std::chrono::system_clock::now() + hours(24); - auto admin = DefaultTableAdmin(); - - EXPECT_CALL(*connection_, UpdateBackup) - .WillOnce([expire_time](btadmin::UpdateBackupRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - EXPECT_EQ(kBackupName, request.backup().name()); - EXPECT_EQ(expire_time, - ToChronoTimePoint(request.backup().expire_time())); - EXPECT_THAT(request.update_mask().paths(), ElementsAre("expire_time")); - return FailingStatus(); - }); - - TableAdmin::UpdateBackupParams params(kClusterId, kBackupId, expire_time); - EXPECT_THAT(admin.UpdateBackup(params), - StatusIs(StatusCode::kPermissionDenied)); -} - -TEST_F(TableAdminTest, DeleteBackup) { - auto admin = DefaultTableAdmin(); - - EXPECT_CALL(*connection_, DeleteBackup) - .Times(2) - .WillRepeatedly([](btadmin::DeleteBackupRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - EXPECT_EQ(kBackupName, request.name()); - return FailingStatus(); - }); - - btadmin::Backup b; - b.set_name(kBackupName); - EXPECT_THAT(admin.DeleteBackup(b), StatusIs(StatusCode::kPermissionDenied)); - - EXPECT_THAT(admin.DeleteBackup(kClusterId, kBackupId), - StatusIs(StatusCode::kPermissionDenied)); -} - -TEST_F(TableAdminTest, ListBackupsParams) { - TableAdmin::ListBackupsParams params; - auto request = params.AsProto(kInstanceName); - EXPECT_EQ(request.parent(), ClusterName(kProjectId, kInstanceId, "-")); - - params.set_cluster(kClusterId).set_filter("state:READY").set_order_by("name"); - request = params.AsProto(kInstanceName); - EXPECT_EQ(request.parent(), kClusterName); - EXPECT_EQ(*request.mutable_filter(), "state:READY"); - EXPECT_EQ(*request.mutable_order_by(), "name"); -} - -TEST_F(TableAdminTest, ListBackupsSuccess) { - auto admin = DefaultTableAdmin(); - std::vector const expected_names = { - BackupName(kProjectId, kInstanceId, kClusterId, "b0"), - BackupName(kProjectId, kInstanceId, kClusterId, "b1")}; - - auto iter = expected_names.begin(); - EXPECT_CALL(*connection_, ListBackups) - .WillOnce([&iter, - &expected_names](btadmin::ListBackupsRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - EXPECT_EQ(kClusterName, request.parent()); - - using ::google::cloud::internal::MakeStreamRange; - using ::google::cloud::internal::StreamReader; - auto reader = - [&iter, - &expected_names]() -> StreamReader::result_type { - if (iter != expected_names.end()) { - btadmin::Backup b; - b.set_name(*iter); - ++iter; - return b; - } - return Status(); - }; - return MakeStreamRange(std::move(reader)); - }); - - auto params = TableAdmin::ListBackupsParams().set_cluster(kClusterId); - auto backups = admin.ListBackups(params); - ASSERT_STATUS_OK(backups); - std::vector names; - std::transform(backups->begin(), backups->end(), std::back_inserter(names), - [](btadmin::Backup const& b) { return b.name(); }); - - EXPECT_THAT(names, ElementsAreArray(expected_names)); -} - -TEST_F(TableAdminTest, ListBackupsFailure) { - auto admin = DefaultTableAdmin(); - - EXPECT_CALL(*connection_, ListBackups) - .WillOnce([](btadmin::ListBackupsRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - EXPECT_EQ(kClusterName, request.parent()); - - using ::google::cloud::internal::MakeStreamRange; - return MakeStreamRange([] { return FailingStatus(); }); - }); - - auto params = TableAdmin::ListBackupsParams().set_cluster(kClusterId); - EXPECT_THAT(admin.ListBackups(params), - StatusIs(StatusCode::kPermissionDenied)); -} - -TEST_F(TableAdminTest, RestoreTableParams) { - TableAdmin::RestoreTableParams params(kTableId, kClusterId, kBackupId); - auto request = params.AsProto(kInstanceName); - EXPECT_EQ(kInstanceName, request.parent()); - EXPECT_EQ(kTableId, request.table_id()); - EXPECT_EQ(kBackupName, request.backup()); -} - -TEST_F(TableAdminTest, RestoreTable) { - auto admin = DefaultTableAdmin(); - - EXPECT_CALL(*connection_, - RestoreTable(An())) - .Times(2) - .WillRepeatedly([](btadmin::RestoreTableRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - EXPECT_EQ(kInstanceName, request.parent()); - EXPECT_EQ(kTableId, request.table_id()); - EXPECT_EQ(kBackupName, request.backup()); - return make_ready_future>(FailingStatus()); - }); - - TableAdmin::RestoreTableParams params(kTableId, kClusterId, kBackupId); - EXPECT_THAT(admin.RestoreTable(params), - StatusIs(StatusCode::kPermissionDenied)); - - TableAdmin::RestoreTableFromInstanceParams instance_params; - instance_params.table_id = kTableId; - instance_params.backup_name = kBackupName; - EXPECT_THAT(admin.RestoreTable(instance_params), - StatusIs(StatusCode::kPermissionDenied)); -} - -TEST_F(TableAdminTest, ModifyColumnFamilies) { - auto admin = DefaultTableAdmin(); - std::string expected_request = R"pb( - name: 'projects/the-project/instances/the-instance/tables/the-table' - modifications { - id: 'foo' - create { gc_rule { max_age { seconds: 172800 } } } - } - modifications { - id: 'bar' - update { gc_rule { max_age { seconds: 86400 } } } - } - )pb"; - - EXPECT_CALL(*connection_, ModifyColumnFamilies) - .WillOnce([&expected_request]( - btadmin::ModifyColumnFamiliesRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - btadmin::ModifyColumnFamiliesRequest expected; - EXPECT_TRUE(google::protobuf::TextFormat::ParseFromString( - expected_request, &expected)); - EXPECT_THAT(expected, IsProtoEqual(request)); - return FailingStatus(); - }); - - using M = ColumnFamilyModification; - std::vector mods = { - M::Create("foo", GcRule::MaxAge(hours(48))), - M::Update("bar", GcRule::MaxAge(hours(24)))}; - EXPECT_THAT(admin.ModifyColumnFamilies(kTableId, mods), - StatusIs(StatusCode::kPermissionDenied)); -} - -TEST_F(TableAdminTest, DropRowsByPrefix) { - auto admin = DefaultTableAdmin(); - - EXPECT_CALL(*connection_, DropRowRange) - .WillOnce([](btadmin::DropRowRangeRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - EXPECT_EQ(kTableName, request.name()); - EXPECT_EQ("prefix", request.row_key_prefix()); - return FailingStatus(); - }); - - EXPECT_THAT(admin.DropRowsByPrefix(kTableId, "prefix"), - StatusIs(StatusCode::kPermissionDenied)); -} - -TEST_F(TableAdminTest, WaitForConsistencySuccess) { - auto admin = DefaultTableAdmin(); - - EXPECT_CALL(*connection_, AsyncCheckConsistency) - .WillOnce([](btadmin::CheckConsistencyRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - EXPECT_EQ(kTableName, request.name()); - EXPECT_EQ("consistency-token", request.consistency_token()); - btadmin::CheckConsistencyResponse resp; - resp.set_consistent(true); - return make_ready_future(make_status_or(resp)); - }); - - auto consistent = - admin.WaitForConsistency(kTableId, "consistency-token").get(); - ASSERT_STATUS_OK(consistent); - EXPECT_EQ(*consistent, Consistency::kConsistent); -} - -TEST_F(TableAdminTest, WaitForConsistencyFailure) { - auto admin = DefaultTableAdmin(); - - EXPECT_CALL(*connection_, AsyncCheckConsistency) - .WillOnce([](btadmin::CheckConsistencyRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - EXPECT_EQ(kTableName, request.name()); - EXPECT_EQ("consistency-token", request.consistency_token()); - return make_ready_future>( - FailingStatus()); - }); - - EXPECT_THAT(admin.WaitForConsistency(kTableId, "consistency-token").get(), - StatusIs(StatusCode::kPermissionDenied)); -} - -TEST_F(TableAdminTest, DropAllRows) { - auto admin = DefaultTableAdmin(); - - EXPECT_CALL(*connection_, DropRowRange) - .WillOnce([](btadmin::DropRowRangeRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - EXPECT_EQ(kTableName, request.name()); - EXPECT_TRUE(request.delete_all_data_from_table()); - return FailingStatus(); - }); - - EXPECT_THAT(admin.DropAllRows(kTableId), - StatusIs(StatusCode::kPermissionDenied)); -} - -TEST_F(TableAdminTest, GenerateConsistencyTokenSuccess) { - auto admin = DefaultTableAdmin(); - - EXPECT_CALL(*connection_, GenerateConsistencyToken) - .WillOnce([](btadmin::GenerateConsistencyTokenRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - EXPECT_EQ(kTableName, request.name()); - btadmin::GenerateConsistencyTokenResponse resp; - resp.set_consistency_token("consistency-token"); - return resp; - }); - - auto token = admin.GenerateConsistencyToken(kTableId); - ASSERT_STATUS_OK(token); - EXPECT_EQ(*token, "consistency-token"); -} - -TEST_F(TableAdminTest, GenerateConsistencyTokenFailure) { - auto admin = DefaultTableAdmin(); - - EXPECT_CALL(*connection_, GenerateConsistencyToken) - .WillOnce([](btadmin::GenerateConsistencyTokenRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - EXPECT_EQ(kTableName, request.name()); - return FailingStatus(); - }); - - EXPECT_THAT(admin.GenerateConsistencyToken(kTableId), - StatusIs(StatusCode::kPermissionDenied)); -} - -TEST_F(TableAdminTest, CheckConsistencySuccess) { - auto admin = DefaultTableAdmin(); - - EXPECT_CALL(*connection_, CheckConsistency) - .WillOnce([](btadmin::CheckConsistencyRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - EXPECT_EQ(kTableName, request.name()); - EXPECT_EQ("consistency-token", request.consistency_token()); - btadmin::CheckConsistencyResponse resp; - resp.set_consistent(false); - return resp; - }) - .WillOnce([](btadmin::CheckConsistencyRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - EXPECT_EQ(kTableName, request.name()); - EXPECT_EQ("consistency-token", request.consistency_token()); - btadmin::CheckConsistencyResponse resp; - resp.set_consistent(true); - return resp; - }); - - auto consistent = admin.CheckConsistency(kTableId, "consistency-token"); - ASSERT_STATUS_OK(consistent); - EXPECT_EQ(*consistent, Consistency::kInconsistent); - - consistent = admin.CheckConsistency(kTableId, "consistency-token"); - ASSERT_STATUS_OK(consistent); - EXPECT_EQ(*consistent, Consistency::kConsistent); -} - -TEST_F(TableAdminTest, CheckConsistencyFailure) { - auto admin = DefaultTableAdmin(); - - EXPECT_CALL(*connection_, CheckConsistency) - .WillOnce([](btadmin::CheckConsistencyRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - EXPECT_EQ(kTableName, request.name()); - EXPECT_EQ("consistency-token", request.consistency_token()); - return FailingStatus(); - }); - - EXPECT_THAT(admin.CheckConsistency(kTableId, "consistency-token"), - StatusIs(StatusCode::kPermissionDenied)); -} - -TEST_F(TableAdminTest, GetIamPolicyTable) { - auto admin = DefaultTableAdmin(); - - EXPECT_CALL(*connection_, GetIamPolicy) - .WillOnce([](iamproto::GetIamPolicyRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - EXPECT_EQ(kTableName, request.resource()); - return FailingStatus(); - }); - - EXPECT_THAT(admin.GetIamPolicy(kTableId), - StatusIs(StatusCode::kPermissionDenied)); -} - -TEST_F(TableAdminTest, GetIamPolicyBackup) { - auto admin = DefaultTableAdmin(); - - EXPECT_CALL(*connection_, GetIamPolicy) - .WillOnce([](iamproto::GetIamPolicyRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - EXPECT_EQ(kBackupName, request.resource()); - return FailingStatus(); - }); - - EXPECT_THAT(admin.GetIamPolicy(kClusterId, kBackupId), - StatusIs(StatusCode::kPermissionDenied)); -} - -TEST_F(TableAdminTest, SetIamPolicyTable) { - auto admin = DefaultTableAdmin(); - - EXPECT_CALL(*connection_, SetIamPolicy) - .WillOnce([](iamproto::SetIamPolicyRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - EXPECT_EQ(kTableName, request.resource()); - EXPECT_EQ(3, request.policy().version()); - EXPECT_EQ("tag", request.policy().etag()); - return FailingStatus(); - }); - - iamproto::Policy p; - p.set_version(3); - p.set_etag("tag"); - EXPECT_THAT(admin.SetIamPolicy(kTableId, p), - StatusIs(StatusCode::kPermissionDenied)); -} - -TEST_F(TableAdminTest, SetIamPolicyBackup) { - auto admin = DefaultTableAdmin(); - - EXPECT_CALL(*connection_, SetIamPolicy) - .WillOnce([](iamproto::SetIamPolicyRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - EXPECT_EQ(kBackupName, request.resource()); - EXPECT_EQ(3, request.policy().version()); - EXPECT_EQ("tag", request.policy().etag()); - return FailingStatus(); - }); - - iamproto::Policy p; - p.set_version(3); - p.set_etag("tag"); - EXPECT_THAT(admin.SetIamPolicy(kClusterId, kBackupId, p), - StatusIs(StatusCode::kPermissionDenied)); -} - -TEST_F(TableAdminTest, TestIamPermissionsTableSuccess) { - auto admin = DefaultTableAdmin(); - std::vector const expected_permissions = {"writer", "reader"}; - std::vector const returned_permissions = {"reader"}; - - EXPECT_CALL(*connection_, TestIamPermissions) - .WillOnce([&](iamproto::TestIamPermissionsRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - EXPECT_EQ(kTableName, request.resource()); - std::vector actual_permissions; - for (auto const& c : request.permissions()) { - actual_permissions.emplace_back(c); - } - EXPECT_THAT(actual_permissions, - UnorderedElementsAreArray(expected_permissions)); - - iamproto::TestIamPermissionsResponse r; - for (auto const& p : returned_permissions) r.add_permissions(p); - return r; - }); - - auto resp = admin.TestIamPermissions(kTableId, expected_permissions); - ASSERT_STATUS_OK(resp); - EXPECT_THAT(*resp, ElementsAreArray(returned_permissions)); -} - -TEST_F(TableAdminTest, TestIamPermissionsTableFailure) { - auto admin = DefaultTableAdmin(); - std::vector const expected_permissions = {"writer", "reader"}; - - EXPECT_CALL(*connection_, TestIamPermissions) - .WillOnce([&](iamproto::TestIamPermissionsRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - EXPECT_EQ(kTableName, request.resource()); - std::vector actual_permissions; - for (auto const& c : request.permissions()) { - actual_permissions.emplace_back(c); - } - EXPECT_THAT(actual_permissions, - UnorderedElementsAreArray(expected_permissions)); - return FailingStatus(); - }); - - EXPECT_THAT(admin.TestIamPermissions(kTableId, expected_permissions), - StatusIs(StatusCode::kPermissionDenied)); -} - -TEST_F(TableAdminTest, TestIamPermissionsBackupSuccess) { - auto admin = DefaultTableAdmin(); - std::vector const expected_permissions = {"writer", "reader"}; - std::vector const returned_permissions = {"reader"}; - - EXPECT_CALL(*connection_, TestIamPermissions) - .WillOnce([&](iamproto::TestIamPermissionsRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - EXPECT_EQ(kBackupName, request.resource()); - std::vector actual_permissions; - for (auto const& c : request.permissions()) { - actual_permissions.emplace_back(c); - } - EXPECT_THAT(actual_permissions, - UnorderedElementsAreArray(expected_permissions)); - - iamproto::TestIamPermissionsResponse r; - for (auto const& p : returned_permissions) r.add_permissions(p); - return r; - }); - - auto resp = - admin.TestIamPermissions(kClusterId, kBackupId, expected_permissions); - ASSERT_STATUS_OK(resp); - EXPECT_THAT(*resp, ElementsAreArray(returned_permissions)); -} - -TEST_F(TableAdminTest, TestIamPermissionsBackupFailure) { - auto admin = DefaultTableAdmin(); - std::vector const expected_permissions = {"writer", "reader"}; - - EXPECT_CALL(*connection_, TestIamPermissions) - .WillOnce([&](iamproto::TestIamPermissionsRequest const& request) { - CheckOptions(google::cloud::internal::CurrentOptions()); - EXPECT_EQ(kBackupName, request.resource()); - std::vector actual_permissions; - for (auto const& c : request.permissions()) { - actual_permissions.emplace_back(c); - } - EXPECT_THAT(actual_permissions, - UnorderedElementsAreArray(expected_permissions)); - return FailingStatus(); - }); - - EXPECT_THAT( - admin.TestIamPermissions(kClusterId, kBackupId, expected_permissions), - StatusIs(StatusCode::kPermissionDenied)); -} - -} // namespace -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END -} // namespace bigtable -} // namespace cloud -} // namespace google diff --git a/google/cloud/bigtable/testing/embedded_server_test_fixture.h b/google/cloud/bigtable/testing/embedded_server_test_fixture.h index 1d2a4403089f8..85908653c1398 100644 --- a/google/cloud/bigtable/testing/embedded_server_test_fixture.h +++ b/google/cloud/bigtable/testing/embedded_server_test_fixture.h @@ -16,7 +16,6 @@ #define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_TESTING_EMBEDDED_SERVER_TEST_FIXTURE_H #include "google/cloud/bigtable/table.h" -#include "google/cloud/bigtable/table_admin.h" #include "google/bigtable/v2/bigtable.grpc.pb.h" #include #include diff --git a/google/cloud/bigtable/testing/table_integration_test.h b/google/cloud/bigtable/testing/table_integration_test.h index c6bbb3574f442..ad2b076ad864c 100644 --- a/google/cloud/bigtable/testing/table_integration_test.h +++ b/google/cloud/bigtable/testing/table_integration_test.h @@ -162,6 +162,16 @@ class TableIntegrationTest return names; } + static StatusOr> TableNames( + StreamRange& tables) { + std::vector names; + for (auto const& table : tables) { + if (!table) return table.status(); + names.push_back(table->name()); + } + return names; + } + static std::vector BackupNames( std::vector const& backups) { std::vector names(backups.size()); diff --git a/google/cloud/bigtable/tests/CMakeLists.txt b/google/cloud/bigtable/tests/CMakeLists.txt index 757872b6b1158..ff7c9e9eb8b04 100644 --- a/google/cloud/bigtable/tests/CMakeLists.txt +++ b/google/cloud/bigtable/tests/CMakeLists.txt @@ -18,14 +18,14 @@ # Bigtable emulator. set(bigtable_client_integration_tests # cmake-format: sort - admin_backup_integration_test.cc - admin_iam_policy_integration_test.cc - admin_integration_test.cc data_async_future_integration_test.cc data_integration_test.cc filters_integration_test.cc instance_admin_integration_test.cc mutations_integration_test.cc + table_admin_backup_integration_test.cc + table_admin_iam_policy_integration_test.cc + table_admin_integration_test.cc table_sample_rows_integration_test.cc) include(CreateBazelConfig) @@ -67,7 +67,8 @@ google_cloud_cpp_add_common_options(${target}) # We just know that these tests need to be run against production. set(bigtable_integration_tests_production # cmake-format: sort - admin_backup_integration_test.cc admin_iam_policy_integration_test.cc) + table_admin_backup_integration_test.cc + table_admin_iam_policy_integration_test.cc) foreach (fname ${bigtable_integration_tests_production}) google_cloud_cpp_set_target_name(target "bigtable" "${fname}") diff --git a/google/cloud/bigtable/tests/bigtable_client_integration_tests.bzl b/google/cloud/bigtable/tests/bigtable_client_integration_tests.bzl index ce7d2f550c98f..907e01e0933dc 100644 --- a/google/cloud/bigtable/tests/bigtable_client_integration_tests.bzl +++ b/google/cloud/bigtable/tests/bigtable_client_integration_tests.bzl @@ -17,13 +17,13 @@ """Automatically generated unit tests list - DO NOT EDIT.""" bigtable_client_integration_tests = [ - "admin_backup_integration_test.cc", - "admin_iam_policy_integration_test.cc", - "admin_integration_test.cc", "data_async_future_integration_test.cc", "data_integration_test.cc", "filters_integration_test.cc", "instance_admin_integration_test.cc", "mutations_integration_test.cc", + "table_admin_backup_integration_test.cc", + "table_admin_iam_policy_integration_test.cc", + "table_admin_integration_test.cc", "table_sample_rows_integration_test.cc", ] diff --git a/google/cloud/bigtable/tests/instance_admin_integration_test.cc b/google/cloud/bigtable/tests/instance_admin_integration_test.cc index 9e47f51ff6196..052dd212ecfb6 100644 --- a/google/cloud/bigtable/tests/instance_admin_integration_test.cc +++ b/google/cloud/bigtable/tests/instance_admin_integration_test.cc @@ -12,7 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "google/cloud/bigtable/instance_admin.h" +#include "google/cloud/bigtable/admin/bigtable_instance_admin_client.h" +#include "google/cloud/bigtable/app_profile_config.h" +#include "google/cloud/bigtable/iam_binding.h" +#include "google/cloud/bigtable/iam_policy.h" +#include "google/cloud/bigtable/instance_config.h" +#include "google/cloud/bigtable/instance_update_config.h" +#include "google/cloud/bigtable/resource_names.h" #include "google/cloud/bigtable/testing/random_names.h" #include "google/cloud/grpc_options.h" #include "google/cloud/internal/algorithm.h" @@ -20,6 +26,7 @@ #include "google/cloud/internal/getenv.h" #include "google/cloud/internal/random.h" #include "google/cloud/location.h" +#include "google/cloud/project.h" #include "google/cloud/status_or.h" #include "google/cloud/testing_util/integration_test.h" #include "google/cloud/testing_util/scoped_environment.h" @@ -64,30 +71,31 @@ class InstanceAdminIntegrationTest GetEnv("GOOGLE_CLOUD_CPP_BIGTABLE_TEST_SERVICE_ACCOUNT").value_or(""); ASSERT_FALSE(service_account_.empty()); - auto instance_admin_client = bigtable::MakeInstanceAdminClient(project_id_); instance_admin_ = - std::make_unique(instance_admin_client); + std::make_unique( + bigtable_admin::MakeBigtableInstanceAdminConnection()); } - std::string project_id_; std::string zone_a_; std::string zone_b_; std::string service_account_; - std::unique_ptr instance_admin_; + std::unique_ptr instance_admin_; google::cloud::internal::DefaultPRNG generator_ = google::cloud::internal::MakeDefaultPRNG(); }; -bool IsInstancePresent(std::vector const& instances, - std::string const& instance_name) { +bool IsInstancePresent( + google::protobuf::RepeatedPtrField const& instances, + std::string const& instance_name) { return google::cloud::internal::ContainsIf( instances, [&instance_name](btadmin::Instance const& i) { return i.name() == instance_name; }); } -bool IsClusterPresent(std::vector const& clusters, - std::string const& cluster_name) { +bool IsClusterPresent( + google::protobuf::RepeatedPtrField const& clusters, + std::string const& cluster_name) { return google::cloud::internal::ContainsIf( clusters, [&cluster_name](btadmin::Cluster const& i) { return i.name() == cluster_name; @@ -121,8 +129,13 @@ TEST_F(InstanceAdminIntegrationTest, ListAllClustersTest) { auto config_2 = IntegrationTestConfig( id_2, zone_b_, bigtable::InstanceConfig::PRODUCTION, 3); - auto instance_1_fut = instance_admin_->CreateInstance(config_1); - auto instance_2_fut = instance_admin_->CreateInstance(config_2); + auto create_request_1 = config_1.as_proto(); + create_request_1.set_parent(Project(project_id_).FullName()); + auto create_request_2 = config_2.as_proto(); + create_request_2.set_parent(Project(project_id_).FullName()); + + auto instance_1_fut = instance_admin_->CreateInstance(create_request_1); + auto instance_2_fut = instance_admin_->CreateInstance(create_request_2); // Wait for instance creation auto instance_1 = instance_1_fut.get(); @@ -133,16 +146,16 @@ TEST_F(InstanceAdminIntegrationTest, ListAllClustersTest) { EXPECT_EQ(instance_1->name(), name_1); EXPECT_EQ(instance_2->name(), name_2); - auto clusters = instance_admin_->ListClusters(); + auto clusters = instance_admin_->ListClusters(instance_1->name()); ASSERT_STATUS_OK(clusters); - for (auto const& cluster : clusters->clusters) { + for (auto const& cluster : clusters->clusters()) { EXPECT_NE(std::string::npos, - cluster.name().find(instance_admin_->project_name())); + cluster.name().find("projects/" + project_id_)); } - EXPECT_FALSE(clusters->clusters.empty()); + EXPECT_FALSE(clusters->clusters().empty()); - EXPECT_STATUS_OK(instance_admin_->DeleteInstance(id_1)); - EXPECT_STATUS_OK(instance_admin_->DeleteInstance(id_2)); + EXPECT_STATUS_OK(instance_admin_->DeleteInstance(name_1)); + EXPECT_STATUS_OK(instance_admin_->DeleteInstance(name_2)); } /// @test Verify that AppProfile CRUD operations work as expected. @@ -152,7 +165,9 @@ TEST_F(InstanceAdminIntegrationTest, CreateListGetDeleteAppProfile) { auto config = IntegrationTestConfig(instance_id, zone_a_, bigtable::InstanceConfig::PRODUCTION, 3); - auto instance_fut = instance_admin_->CreateInstance(config); + auto create_request = config.as_proto(); + create_request.set_parent(Project(project_id_).FullName()); + auto instance_fut = instance_admin_->CreateInstance(create_request); // Wait for instance creation auto instance = instance_fut.get(); ASSERT_STATUS_OK(instance); @@ -168,67 +183,83 @@ TEST_F(InstanceAdminIntegrationTest, CreateListGetDeleteAppProfile) { auto const name_2 = bigtable::AppProfileName(project_id_, instance_id, id_2); // Simplify writing the rest of the test. - auto profile_names = [](std::vector const& list) { - std::vector names(list.size()); - std::transform(list.begin(), list.end(), names.begin(), - [](btadmin::AppProfile const& x) { return x.name(); }); + auto profile_names = [](StreamRange& list) + -> StatusOr> { + std::vector names; + for (auto const& p : list) { + if (!p) return p.status(); + names.push_back(p->name()); + } return names; }; - auto profiles = instance_admin_->ListAppProfiles(instance_id); - ASSERT_STATUS_OK(profiles); - EXPECT_THAT(profile_names(*profiles), Not(Contains(name_1))); - EXPECT_THAT(profile_names(*profiles), Not(Contains(name_2))); - - auto profile_1 = instance_admin_->CreateAppProfile( - instance_id, bigtable::AppProfileConfig::MultiClusterUseAny(id_1)); + auto profiles = instance_admin_->ListAppProfiles(instance_name); + auto names = profile_names(profiles); + ASSERT_STATUS_OK(names); + EXPECT_THAT(*names, Not(Contains(name_1))); + EXPECT_THAT(*names, Not(Contains(name_2))); + + auto create_profile_request = + bigtable::AppProfileConfig::MultiClusterUseAny(id_1).as_proto(); + create_profile_request.set_parent(instance_name); + create_profile_request.set_app_profile_id(id_1); + auto profile_1 = instance_admin_->CreateAppProfile(create_profile_request); ASSERT_STATUS_OK(profile_1); EXPECT_EQ(profile_1->name(), name_1); - auto profile_2 = instance_admin_->CreateAppProfile( - instance_id, bigtable::AppProfileConfig::MultiClusterUseAny(id_2)); + create_profile_request = + bigtable::AppProfileConfig::MultiClusterUseAny(id_2).as_proto(); + create_profile_request.set_parent(instance_name); + create_profile_request.set_app_profile_id(id_2); + auto profile_2 = instance_admin_->CreateAppProfile(create_profile_request); ASSERT_STATUS_OK(profile_2); EXPECT_EQ(profile_2->name(), name_2); - profiles = instance_admin_->ListAppProfiles(instance_id); - ASSERT_STATUS_OK(profiles); - EXPECT_THAT(profile_names(*profiles), Contains(name_1).Times(1)); - EXPECT_THAT(profile_names(*profiles), Contains(name_2).Times(1)); + profiles = instance_admin_->ListAppProfiles(instance_name); + names = profile_names(profiles); + ASSERT_STATUS_OK(names); + EXPECT_THAT(*names, Contains(name_1).Times(1)); + EXPECT_THAT(*names, Contains(name_2).Times(1)); - profile_1 = instance_admin_->GetAppProfile(instance_id, id_1); + profile_1 = instance_admin_->GetAppProfile( + AppProfileName(project_id_, instance_id, id_1)); ASSERT_STATUS_OK(profile_1); EXPECT_EQ(profile_1->name(), name_1); - profile_2 = instance_admin_->GetAppProfile(instance_id, id_2); + profile_2 = instance_admin_->GetAppProfile( + AppProfileName(project_id_, instance_id, id_2)); ASSERT_STATUS_OK(profile_2); EXPECT_EQ(profile_2->name(), name_2); - profile_2 = - instance_admin_ - ->UpdateAppProfile(instance_id, id_2, - bigtable::AppProfileUpdateConfig().set_description( - "new description")) - .get(); + profile_2->set_description("new description"); + google::protobuf::FieldMask field_mask; + *field_mask.add_paths() = "description"; + profile_2 = instance_admin_->UpdateAppProfile(*profile_2, field_mask).get(); ASSERT_STATUS_OK(profile_2); EXPECT_EQ("new description", profile_2->description()); - profile_2 = instance_admin_->GetAppProfile(instance_id, id_2); + profile_2 = instance_admin_->GetAppProfile( + AppProfileName(project_id_, instance_id, id_2)); ASSERT_STATUS_OK(profile_2); EXPECT_EQ("new description", profile_2->description()); - ASSERT_STATUS_OK(instance_admin_->DeleteAppProfile(instance_id, id_1, true)); - profiles = instance_admin_->ListAppProfiles(instance_id); - ASSERT_STATUS_OK(profiles); - EXPECT_THAT(profile_names(*profiles), Not(Contains(name_1))); - EXPECT_THAT(profile_names(*profiles), Contains(name_2).Times(1)); - - ASSERT_STATUS_OK(instance_admin_->DeleteAppProfile(instance_id, id_2, true)); - profiles = instance_admin_->ListAppProfiles(instance_id); - ASSERT_STATUS_OK(profiles); - EXPECT_THAT(profile_names(*profiles), Not(Contains(name_1))); - EXPECT_THAT(profile_names(*profiles), Not(Contains(name_2))); - - ASSERT_STATUS_OK(instance_admin_->DeleteInstance(instance_id)); + ASSERT_STATUS_OK(instance_admin_->DeleteAppProfile( + AppProfileName(project_id_, instance_id, id_1), true)); + profiles = instance_admin_->ListAppProfiles(instance_name); + names = profile_names(profiles); + ASSERT_STATUS_OK(names); + EXPECT_THAT((*names), Not(Contains(name_1))); + EXPECT_THAT(*names, Contains(name_2).Times(1)); + + ASSERT_STATUS_OK(instance_admin_->DeleteAppProfile( + AppProfileName(project_id_, instance_id, id_2), true)); + profiles = instance_admin_->ListAppProfiles(instance_name); + names = profile_names(profiles); + ASSERT_STATUS_OK(names); + EXPECT_THAT(*names, Not(Contains(name_1))); + EXPECT_THAT(*names, Not(Contains(name_2))); + + ASSERT_STATUS_OK(instance_admin_->DeleteInstance(instance_name)); } /// @test Verify that Instance CRUD operations work as expected. @@ -238,24 +269,27 @@ TEST_F(InstanceAdminIntegrationTest, CreateListGetDeleteInstanceTest) { // Create instance auto config = IntegrationTestConfig(instance_id, zone_a_); - auto instance = instance_admin_->CreateInstance(config).get(); + auto create_request = config.as_proto(); + create_request.set_parent(Project(project_id_).FullName()); + auto instance = instance_admin_->CreateInstance(create_request).get(); ASSERT_STATUS_OK(instance); - auto const zone_a = Location(instance_admin_->project_name(), zone_a_); - auto const zone_b = Location(instance_admin_->project_name(), zone_b_); + auto project = google::cloud::Project(project_id_); + auto const zone_a = Location(project.FullName(), zone_a_); + auto const zone_b = Location(project.FullName(), zone_b_); // List instances - auto instances = instance_admin_->ListInstances(); + auto instances = instance_admin_->ListInstances(project.FullName()); ASSERT_STATUS_OK(instances); // If either zone_a_ or zone_b_ are in the list of failed locations then we // cannot proceed. ASSERT_THAT( - instances->failed_locations, + instances->failed_locations(), Not(AnyOf(Contains(zone_a.FullName()), Contains(zone_b.FullName())))); - EXPECT_TRUE(IsInstancePresent(instances->instances, instance->name())); + EXPECT_TRUE(IsInstancePresent(instances->instances(), instance->name())); // Get instance - instance = instance_admin_->GetInstance(instance_id); + instance = instance_admin_->GetInstance(instance_name); ASSERT_STATUS_OK(instance); EXPECT_EQ(instance->name(), instance_name); @@ -264,31 +298,33 @@ TEST_F(InstanceAdminIntegrationTest, CreateListGetDeleteInstanceTest) { auto const updated_display_name = instance_id.substr(0, 22) + " updated"; instance_update_config.set_display_name(updated_display_name); instance = - instance_admin_->UpdateInstance(std::move(instance_update_config)).get(); + instance_admin_->PartialUpdateInstance(instance_update_config.as_proto()) + .get(); ASSERT_STATUS_OK(instance); // Verify update - instance = instance_admin_->GetInstance(instance_id); + instance = instance_admin_->GetInstance(instance_name); ASSERT_STATUS_OK(instance); EXPECT_EQ(updated_display_name, instance->display_name()); // Delete instance - ASSERT_STATUS_OK(instance_admin_->DeleteInstance(instance_id)); + ASSERT_STATUS_OK(instance_admin_->DeleteInstance(instance_name)); // Verify delete - instances = instance_admin_->ListInstances(); + instances = instance_admin_->ListInstances(project.FullName()); ASSERT_STATUS_OK(instances); // If either zone_a_ or zone_b_ are in the list of failed locations then we // cannot proceed. ASSERT_THAT( - instances->failed_locations, + instances->failed_locations(), Not(AnyOf(Contains(zone_a.FullName()), Contains(zone_b.FullName())))); - EXPECT_FALSE(IsInstancePresent(instances->instances, instance_name)); + EXPECT_FALSE(IsInstancePresent(instances->instances(), instance_name)); } /// @test Verify that cluster CRUD operations work as expected. TEST_F(InstanceAdminIntegrationTest, CreateListGetDeleteClusterTest) { auto const instance_id = RandomInstanceId(generator_); + auto const instance_name = InstanceName(project_id_, instance_id); auto const cluster_id = instance_id + "-cl2"; auto const cluster_name = bigtable::ClusterName(project_id_, instance_id, cluster_id); @@ -296,25 +332,28 @@ TEST_F(InstanceAdminIntegrationTest, CreateListGetDeleteClusterTest) { // Create instance prerequisites for cluster operations auto config = IntegrationTestConfig(instance_id, zone_a_, bigtable::InstanceConfig::PRODUCTION, 3); - auto instance = instance_admin_->CreateInstance(config).get(); + auto create_request = config.as_proto(); + create_request.set_parent(Project(project_id_).FullName()); + auto instance = instance_admin_->CreateInstance(create_request).get(); ASSERT_STATUS_OK(instance); // Create cluster auto cluster_config = bigtable::ClusterConfig(zone_b_, 3, bigtable::ClusterConfig::HDD); auto cluster = - instance_admin_->CreateCluster(cluster_config, instance_id, cluster_id) + instance_admin_ + ->CreateCluster(instance_name, cluster_id, cluster_config.as_proto()) .get(); ASSERT_STATUS_OK(cluster); EXPECT_EQ(3, cluster->serve_nodes()); // Verify create - auto clusters = instance_admin_->ListClusters(instance_id); + auto clusters = instance_admin_->ListClusters(instance_name); ASSERT_STATUS_OK(clusters); - EXPECT_TRUE(IsClusterPresent(clusters->clusters, cluster->name())); + EXPECT_TRUE(IsClusterPresent(clusters->clusters(), cluster->name())); // Get cluster - cluster = instance_admin_->GetCluster(instance_id, cluster_id); + cluster = instance_admin_->GetCluster(cluster_name); ASSERT_STATUS_OK(cluster); EXPECT_EQ(cluster_name, cluster->name()); @@ -323,53 +362,57 @@ TEST_F(InstanceAdminIntegrationTest, CreateListGetDeleteClusterTest) { cluster->clear_state(); bigtable::ClusterConfig updated_cluster_config(std::move(*cluster)); cluster = - instance_admin_->UpdateCluster(std::move(updated_cluster_config)).get(); + instance_admin_->UpdateCluster(updated_cluster_config.as_proto()).get(); ASSERT_STATUS_OK(cluster); // Verify update - cluster = instance_admin_->GetCluster(instance_id, cluster_id); + cluster = instance_admin_->GetCluster(cluster_name); ASSERT_STATUS_OK(cluster); EXPECT_EQ(4, cluster->serve_nodes()); // Delete cluster - ASSERT_STATUS_OK(instance_admin_->DeleteCluster(instance_id, cluster_id)); + ASSERT_STATUS_OK(instance_admin_->DeleteCluster(cluster_name)); // Verify delete - clusters = instance_admin_->ListClusters(instance_id); + clusters = instance_admin_->ListClusters(instance_name); ASSERT_STATUS_OK(clusters); - EXPECT_FALSE(IsClusterPresent(clusters->clusters, cluster_name)); + EXPECT_FALSE(IsClusterPresent(clusters->clusters(), cluster_name)); // Delete instance - ASSERT_STATUS_OK(instance_admin_->DeleteInstance(instance_id)); + ASSERT_STATUS_OK(instance_admin_->DeleteInstance(instance_name)); } /// @test Verify that IAM Policy Native APIs work as expected. TEST_F(InstanceAdminIntegrationTest, SetGetTestIamNativeAPIsTest) { auto const instance_id = RandomInstanceId(generator_); + auto const instance_name = InstanceName(project_id_, instance_id); // create instance prerequisites for cluster operations auto config = IntegrationTestConfig(instance_id, zone_a_, bigtable::InstanceConfig::PRODUCTION, 3); - ASSERT_STATUS_OK(instance_admin_->CreateInstance(config).get()); + auto create_request = config.as_proto(); + create_request.set_parent(Project(project_id_).FullName()); + ASSERT_STATUS_OK(instance_admin_->CreateInstance(create_request).get()); auto iam_policy = bigtable::IamPolicy({bigtable::IamBinding( "roles/bigtable.reader", {"serviceAccount:" + service_account_})}); - auto initial_policy = instance_admin_->SetIamPolicy(instance_id, iam_policy); + auto initial_policy = + instance_admin_->SetIamPolicy(instance_name, iam_policy); ASSERT_STATUS_OK(initial_policy); - auto fetched_policy = instance_admin_->GetNativeIamPolicy(instance_id); + auto fetched_policy = instance_admin_->GetIamPolicy(instance_name); ASSERT_STATUS_OK(fetched_policy); EXPECT_EQ(initial_policy->version(), fetched_policy->version()); EXPECT_EQ(initial_policy->etag(), fetched_policy->etag()); auto permission_set = instance_admin_->TestIamPermissions( - instance_id, {"bigtable.tables.list", "bigtable.tables.delete"}); + instance_name, {"bigtable.tables.list", "bigtable.tables.delete"}); ASSERT_STATUS_OK(permission_set); - EXPECT_EQ(2, permission_set->size()); - EXPECT_STATUS_OK(instance_admin_->DeleteInstance(instance_id)); + EXPECT_EQ(2, permission_set->permissions().size()); + EXPECT_STATUS_OK(instance_admin_->DeleteInstance(instance_name)); } /// @test Verify that Instance CRUD operations with logging work as expected. @@ -383,32 +426,34 @@ TEST_F(InstanceAdminIntegrationTest, testing_util::ScopedLog log; auto const instance_id = RandomInstanceId(generator_); auto const instance_name = bigtable::InstanceName(project_id_, instance_id); - - auto instance_admin_client = bigtable::MakeInstanceAdminClient( - project_id_, Options{}.set({"rpc"})); + Project const project(project_id_); auto instance_admin = - std::make_unique(instance_admin_client); + std::make_unique( + bigtable_admin::MakeBigtableInstanceAdminConnection( + Options{}.set({"rpc"}))); - auto const zone_a = Location(instance_admin_->project_name(), zone_a_); - auto const zone_b = Location(instance_admin_->project_name(), zone_b_); + auto const zone_a = Location(project.FullName(), zone_a_); + auto const zone_b = Location(project.FullName(), zone_b_); // Create instance auto config = IntegrationTestConfig(instance_id, zone_a_); - auto instance = instance_admin->CreateInstance(config).get(); + auto create_request = config.as_proto(); + create_request.set_parent(project.FullName()); + auto instance = instance_admin->CreateInstance(create_request).get(); ASSERT_STATUS_OK(instance); // Verify create - auto instances = instance_admin->ListInstances(); + auto instances = instance_admin->ListInstances(project.FullName()); ASSERT_STATUS_OK(instances); // If either zone_a_ or zone_b_ are in the list of failed locations then we // cannot proceed. ASSERT_THAT( - instances->failed_locations, + instances->failed_locations(), Not(AnyOf(Contains(zone_a.FullName()), Contains(zone_b.FullName())))); - EXPECT_TRUE(IsInstancePresent(instances->instances, instance->name())); + EXPECT_TRUE(IsInstancePresent(instances->instances(), instance->name())); // Get instance - instance = instance_admin->GetInstance(instance_id); + instance = instance_admin->GetInstance(instance_name); ASSERT_STATUS_OK(instance); EXPECT_EQ(instance->name(), instance_name); @@ -417,26 +462,27 @@ TEST_F(InstanceAdminIntegrationTest, auto const updated_display_name = instance_id.substr(0, 22) + " updated"; instance_update_config.set_display_name(updated_display_name); instance = - instance_admin->UpdateInstance(std::move(instance_update_config)).get(); + instance_admin->PartialUpdateInstance(instance_update_config.as_proto()) + .get(); ASSERT_STATUS_OK(instance); // Verify update - instance = instance_admin->GetInstance(instance_id); + instance = instance_admin->GetInstance(instance_name); ASSERT_STATUS_OK(instance); EXPECT_EQ(updated_display_name, instance->display_name()); // Delete instance - ASSERT_STATUS_OK(instance_admin->DeleteInstance(instance_id)); + ASSERT_STATUS_OK(instance_admin->DeleteInstance(instance_name)); // Verify delete - instances = instance_admin->ListInstances(); + instances = instance_admin->ListInstances(project.FullName()); ASSERT_STATUS_OK(instances); // If either zone_a_ or zone_b_ are in the list of failed locations then we // cannot proceed. ASSERT_THAT( - instances->failed_locations, + instances->failed_locations(), Not(AnyOf(Contains(zone_a.FullName()), Contains(zone_b.FullName())))); - EXPECT_FALSE(IsInstancePresent(instances->instances, instance_name)); + EXPECT_FALSE(IsInstancePresent(instances->instances(), instance_name)); auto const log_lines = log.ExtractLines(); EXPECT_THAT(log_lines, Contains(HasSubstr("ListInstances"))); @@ -446,22 +492,28 @@ TEST_F(InstanceAdminIntegrationTest, EXPECT_THAT(log_lines, Contains(HasSubstr("DeleteInstance"))); // Verify that a normal client does not log. - auto no_logging_client = InstanceAdmin(MakeInstanceAdminClient(project_id_)); - (void)no_logging_client.ListInstances(); + auto no_logging_client = + std::make_unique( + bigtable_admin::MakeBigtableInstanceAdminConnection()); + (void)no_logging_client->ListInstances(project.FullName()); EXPECT_THAT(log.ExtractLines(), Not(Contains(HasSubstr("ListInstances")))); } TEST_F(InstanceAdminIntegrationTest, CustomWorkers) { CompletionQueue cq; - auto instance_admin_client = bigtable::MakeInstanceAdminClient( - project_id_, Options{}.set(cq)); instance_admin_ = - std::make_unique(instance_admin_client); + std::make_unique( + bigtable_admin::MakeBigtableInstanceAdminConnection( + Options{}.set(cq))); // CompletionQueue `cq` is not being `Run()`, so this should never finish. auto const instance_id = RandomInstanceId(generator_); - auto instance_fut = instance_admin_->CreateInstance(IntegrationTestConfig( - instance_id, zone_a_, bigtable::InstanceConfig::PRODUCTION, 3)); + auto create_request = + IntegrationTestConfig(instance_id, zone_a_, + bigtable::InstanceConfig::PRODUCTION, 3) + .as_proto(); + create_request.set_parent(Project(project_id_).FullName()); + auto instance_fut = instance_admin_->CreateInstance(create_request); EXPECT_EQ(std::future_status::timeout, instance_fut.wait_for(std::chrono::milliseconds(100))); @@ -469,13 +521,13 @@ TEST_F(InstanceAdminIntegrationTest, CustomWorkers) { std::thread t([cq]() mutable { cq.Run(); }); auto instance = instance_fut.get(); ASSERT_STATUS_OK(instance); - EXPECT_STATUS_OK(instance_admin_->DeleteInstance(instance_id)); + EXPECT_STATUS_OK( + instance_admin_->DeleteInstance(InstanceName(project_id_, instance_id))); cq.CancelAll(); cq.Shutdown(); t.join(); } - } // namespace GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END } // namespace bigtable diff --git a/google/cloud/bigtable/tests/admin_backup_integration_test.cc b/google/cloud/bigtable/tests/table_admin_backup_integration_test.cc similarity index 55% rename from google/cloud/bigtable/tests/admin_backup_integration_test.cc rename to google/cloud/bigtable/tests/table_admin_backup_integration_test.cc index 98e663204ded1..be2795cbfe721 100644 --- a/google/cloud/bigtable/tests/admin_backup_integration_test.cc +++ b/google/cloud/bigtable/tests/table_admin_backup_integration_test.cc @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "google/cloud/bigtable/instance_admin.h" -#include "google/cloud/bigtable/table_admin.h" +#include "google/cloud/bigtable/admin/bigtable_instance_admin_client.h" +#include "google/cloud/bigtable/admin/bigtable_table_admin_client.h" #include "google/cloud/bigtable/testing/table_integration_test.h" #include "google/cloud/internal/getenv.h" #include "google/cloud/internal/random.h" @@ -41,22 +41,17 @@ namespace bigtable = ::google::cloud::bigtable; class AdminBackupIntegrationTest : public bigtable::testing::TableIntegrationTest { protected: - std::unique_ptr table_admin_; - std::unique_ptr instance_admin_; - void SetUp() override { TableIntegrationTest::SetUp(); - - std::shared_ptr admin_client = - bigtable::MakeAdminClient( - bigtable::testing::TableTestEnvironment::project_id()); - table_admin_ = std::make_unique( - admin_client, bigtable::testing::TableTestEnvironment::instance_id()); - auto instance_admin_client = bigtable::MakeInstanceAdminClient( - bigtable::testing::TableTestEnvironment::project_id()); + table_admin_ = std::make_unique( + bigtable_admin::MakeBigtableTableAdminConnection()); instance_admin_ = - std::make_unique(instance_admin_client); + std::make_unique( + bigtable_admin::MakeBigtableInstanceAdminConnection()); } + + std::unique_ptr table_admin_; + std::unique_ptr instance_admin_; }; /// @test Verify that `bigtable::TableAdmin` Backup CRUD operations work as @@ -66,14 +61,16 @@ TEST_F(AdminBackupIntegrationTest, CreateListGetUpdateRestoreDeleteBackup) { auto const table_name = bigtable::TableName(project_id(), instance_id(), table_id); - auto clusters = instance_admin_->ListClusters(table_admin_->instance_id()); + auto clusters = instance_admin_->ListClusters( + bigtable::InstanceName(project_id(), instance_id())); ASSERT_STATUS_OK(clusters); - auto const cluster_name = clusters->clusters.begin()->name(); + auto const cluster_name = clusters->clusters().begin()->name(); auto const cluster_id = cluster_name.substr(cluster_name.rfind('/') + 1, cluster_name.size() - cluster_name.rfind('/')); auto const backup_id = RandomBackupId(); - auto const backup_name = cluster_name + "/backups/" + backup_id; + auto backup_name = + bigtable::BackupName(project_id(), instance_id(), cluster_id, backup_id); // Create backup // The proto documentation says backup expiration times are in "microseconds @@ -82,28 +79,42 @@ TEST_F(AdminBackupIntegrationTest, CreateListGetUpdateRestoreDeleteBackup) { auto expire_time = std::chrono::time_point_cast( std::chrono::system_clock::now() + std::chrono::hours(12)); - auto backup = table_admin_->CreateBackup( - {cluster_id, backup_id, table_id, expire_time}); + google::bigtable::admin::v2::Backup b; + *b.mutable_expire_time() = ToProtoTimestamp(expire_time); + auto backup = table_admin_ + ->CreateBackup(bigtable::ClusterName( + project_id(), instance_id(), cluster_id), + backup_id, b) + .get(); + ASSERT_STATUS_OK(backup); EXPECT_EQ(backup->name(), backup_name); // List backups to verify new backup has been created - auto backups = table_admin_->ListBackups({}); - ASSERT_STATUS_OK(backups); - EXPECT_THAT(BackupNames(*backups), Contains(backup_name)); + auto backups = table_admin_->ListBackups(table_name); + std::vector backups_list; + for (auto& b : backups) { + ASSERT_STATUS_OK(b); + backups_list.push_back(*b); + } + EXPECT_THAT(BackupNames(backups_list), Contains(backup_name)); // Get backup to verify create - backup = table_admin_->GetBackup(cluster_id, backup_id); + backup = table_admin_->GetBackup(backup_name); ASSERT_STATUS_OK(backup); EXPECT_EQ(backup->name(), backup_name); // Update backup expire_time += std::chrono::hours(12); - backup = table_admin_->UpdateBackup({cluster_id, backup_id, expire_time}); + google::bigtable::admin::v2::Backup update_backup = *backup; + *update_backup.mutable_expire_time() = ToProtoTimestamp(expire_time); + google::protobuf::FieldMask update_mask; + update_mask.add_paths("expire_time"); + backup = table_admin_->UpdateBackup(update_backup, update_mask); ASSERT_STATUS_OK(backup); // Verify the update - backup = table_admin_->GetBackup(cluster_id, backup_id); + backup = table_admin_->GetBackup(backup_name); ASSERT_STATUS_OK(backup); EXPECT_EQ(backup->name(), backup_name); EXPECT_THAT(backup->expire_time(), @@ -113,21 +124,37 @@ TEST_F(AdminBackupIntegrationTest, CreateListGetUpdateRestoreDeleteBackup) { EXPECT_STATUS_OK(table_admin_->DeleteTable(table_id)); // Verify the delete - auto tables = table_admin_->ListTables(btadmin::Table::NAME_ONLY); - ASSERT_STATUS_OK(tables); - EXPECT_THAT(TableNames(*tables), Not(Contains(table_name))); + google::bigtable::admin::v2::ListTablesRequest list_request; + list_request.set_parent(bigtable::InstanceName(project_id(), instance_id())); + list_request.set_view(btadmin::Table::NAME_ONLY); + auto tables = table_admin_->ListTables(list_request); + std::vector table_list; + for (auto& t : tables) { + ASSERT_STATUS_OK(t); + table_list.push_back(*t); + } + EXPECT_THAT(TableNames(table_list), Not(Contains(table_name))); // Restore table - auto table = table_admin_->RestoreTable({table_id, cluster_id, backup_id}); + google::bigtable::admin::v2::RestoreTableRequest restore_request; + restore_request.set_parent( + bigtable::InstanceName(project_id(), instance_id())); + restore_request.set_backup(backup_name); + restore_request.set_table_id(table_name); + auto table = table_admin_->RestoreTable(restore_request).get(); EXPECT_STATUS_OK(table); // Verify the restore - tables = table_admin_->ListTables(btadmin::Table::NAME_ONLY); - ASSERT_STATUS_OK(tables); - EXPECT_THAT(TableNames(*tables), Contains(table_name).Times(1)); + tables = table_admin_->ListTables(list_request); + table_list.clear(); + for (auto& t : tables) { + ASSERT_STATUS_OK(t); + table_list.push_back(*t); + } + EXPECT_THAT(TableNames(table_list), Contains(table_name).Times(1)); // Delete backup - EXPECT_STATUS_OK(table_admin_->DeleteBackup(cluster_id, backup_id)); + EXPECT_STATUS_OK(table_admin_->DeleteBackup(backup_name)); } } // namespace diff --git a/google/cloud/bigtable/tests/admin_iam_policy_integration_test.cc b/google/cloud/bigtable/tests/table_admin_iam_policy_integration_test.cc similarity index 76% rename from google/cloud/bigtable/tests/admin_iam_policy_integration_test.cc rename to google/cloud/bigtable/tests/table_admin_iam_policy_integration_test.cc index 9a0a531325226..fd7927804e961 100644 --- a/google/cloud/bigtable/tests/admin_iam_policy_integration_test.cc +++ b/google/cloud/bigtable/tests/table_admin_iam_policy_integration_test.cc @@ -12,8 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "google/cloud/bigtable/instance_admin.h" -#include "google/cloud/bigtable/table_admin.h" +#include "google/cloud/bigtable/admin/bigtable_table_admin_client.h" +#include "google/cloud/bigtable/iam_binding.h" +#include "google/cloud/bigtable/iam_policy.h" #include "google/cloud/bigtable/testing/table_integration_test.h" #include "google/cloud/internal/getenv.h" #include "google/cloud/testing_util/chrono_literals.h" @@ -29,10 +30,6 @@ namespace { class AdminIAMPolicyIntegrationTest : public bigtable::testing::TableIntegrationTest { protected: - std::shared_ptr admin_client_; - std::unique_ptr table_admin_; - std::string service_account_; - void SetUp() override { TableIntegrationTest::SetUp(); @@ -41,34 +38,37 @@ class AdminIAMPolicyIntegrationTest .value_or(""); ASSERT_FALSE(service_account_.empty()); - admin_client_ = - MakeAdminClient(testing::TableTestEnvironment::project_id()); - table_admin_ = std::make_unique( - admin_client_, bigtable::testing::TableTestEnvironment::instance_id()); + table_admin_ = std::make_unique( + bigtable_admin::MakeBigtableTableAdminConnection()); } + + std::string service_account_; + std::unique_ptr table_admin_; }; /// @test Verify that IAM Policy APIs work as expected. TEST_F(AdminIAMPolicyIntegrationTest, SetGetTestIamAPIsTest) { auto const table_id = bigtable::testing::TableTestEnvironment::table_id(); + auto table_name = bigtable::TableName(project_id(), instance_id(), table_id); + auto iam_policy = bigtable::IamPolicy({bigtable::IamBinding( "roles/bigtable.reader", {"serviceAccount:" + service_account_})}); - auto initial_policy = table_admin_->SetIamPolicy(table_id, iam_policy); + auto initial_policy = table_admin_->SetIamPolicy(table_name, iam_policy); ASSERT_STATUS_OK(initial_policy); - auto fetched_policy = table_admin_->GetIamPolicy(table_id); + auto fetched_policy = table_admin_->GetIamPolicy(table_name); ASSERT_STATUS_OK(fetched_policy); EXPECT_EQ(initial_policy->version(), fetched_policy->version()); EXPECT_EQ(initial_policy->etag(), fetched_policy->etag()); auto permission_set = table_admin_->TestIamPermissions( - table_id, {"bigtable.tables.get", "bigtable.tables.readRows"}); + table_name, {"bigtable.tables.get", "bigtable.tables.readRows"}); ASSERT_STATUS_OK(permission_set); - EXPECT_EQ(2, permission_set->size()); + EXPECT_EQ(2, permission_set->permissions().size()); } } // namespace diff --git a/google/cloud/bigtable/tests/admin_integration_test.cc b/google/cloud/bigtable/tests/table_admin_integration_test.cc similarity index 60% rename from google/cloud/bigtable/tests/admin_integration_test.cc rename to google/cloud/bigtable/tests/table_admin_integration_test.cc index 456343334b381..c51760adefdc3 100644 --- a/google/cloud/bigtable/tests/admin_integration_test.cc +++ b/google/cloud/bigtable/tests/table_admin_integration_test.cc @@ -12,9 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "google/cloud/bigtable/instance_admin.h" -#include "google/cloud/bigtable/table_admin.h" +#include "google/cloud/bigtable/admin/bigtable_instance_admin_client.h" +#include "google/cloud/bigtable/admin/bigtable_table_admin_client.h" +#include "google/cloud/bigtable/cluster_config.h" +#include "google/cloud/bigtable/instance_config.h" +#include "google/cloud/bigtable/table_config.h" #include "google/cloud/bigtable/testing/table_integration_test.h" +#include "google/cloud/bigtable/wait_for_consistency.h" +#include "google/cloud/common_options.h" #include "google/cloud/internal/getenv.h" #include "google/cloud/internal/random.h" #include "google/cloud/testing_util/chrono_literals.h" @@ -38,53 +43,65 @@ using ::testing::Not; namespace btadmin = ::google::bigtable::admin::v2; -class AdminIntegrationTest : public bigtable::testing::TableIntegrationTest { +class TableAdminIntegrationTest + : public bigtable::testing::TableIntegrationTest { protected: - std::unique_ptr table_admin_; + std::unique_ptr table_admin_; void SetUp() override { TableIntegrationTest::SetUp(); - std::shared_ptr admin_client = - bigtable::MakeAdminClient( - bigtable::testing::TableTestEnvironment::project_id()); - table_admin_ = std::make_unique( - admin_client, bigtable::testing::TableTestEnvironment::instance_id()); + table_admin_ = std::make_unique( + bigtable_admin::MakeBigtableTableAdminConnection()); } }; -TEST_F(AdminIntegrationTest, TableListWithMultipleTables) { +TEST_F(TableAdminIntegrationTest, TableListWithMultipleTables) { std::vector ids; std::vector expected_tables; + auto instance_name = bigtable::InstanceName(project_id(), instance_id()); + // Create tables int constexpr kTableCount = 5; for (int index = 0; index < kTableCount; ++index) { std::string table_id = RandomTableId(); - EXPECT_STATUS_OK(table_admin_->CreateTable(table_id, {})); + EXPECT_STATUS_OK(table_admin_->CreateTable(instance_name, table_id, {})); ids.emplace_back(table_id); expected_tables.emplace_back( bigtable::TableName(project_id(), instance_id(), std::move(table_id))); } - auto tables = table_admin_->ListTables(btadmin::Table::NAME_ONLY); - ASSERT_STATUS_OK(tables); - EXPECT_THAT(TableNames(*tables), IsSupersetOf(expected_tables)); + google::bigtable::admin::v2::ListTablesRequest list_request; + list_request.set_parent(instance_name); + list_request.set_view(btadmin::Table::NAME_ONLY); + auto tables = table_admin_->ListTables(list_request); + std::vector table_list; + for (auto& t : tables) { + ASSERT_STATUS_OK(t); + table_list.push_back(*t); + } + EXPECT_THAT(TableNames(table_list), IsSupersetOf(expected_tables)); // Delete the tables so future tests have a clean slate. for (auto const& table_id : ids) { - EXPECT_STATUS_OK(table_admin_->DeleteTable(table_id)); + EXPECT_STATUS_OK(table_admin_->DeleteTable( + TableName(project_id(), instance_id(), table_id))); } // Verify the tables were deleted. - tables = table_admin_->ListTables(btadmin::Table::NAME_ONLY); - ASSERT_STATUS_OK(tables); - auto names = TableNames(*tables); + tables = table_admin_->ListTables(list_request); + table_list.clear(); + for (auto& t : tables) { + ASSERT_STATUS_OK(t); + table_list.push_back(*t); + } + auto names = TableNames(table_list); for (auto const& t : expected_tables) { EXPECT_THAT(names, Not(Contains(t))); } } -TEST_F(AdminIntegrationTest, DropRowsByPrefix) { +TEST_F(TableAdminIntegrationTest, DropRowsByPrefix) { auto table = GetTable(); // Create a vector of cell which will be inserted into bigtable @@ -109,14 +126,15 @@ TEST_F(AdminIntegrationTest, DropRowsByPrefix) { // Create records CreateCells(table, created_cells); // Delete all the records for a row - EXPECT_STATUS_OK(table_admin_->DropRowsByPrefix( - bigtable::testing::TableTestEnvironment::table_id(), row_key1_prefix)); + google::bigtable::admin::v2::DropRowRangeRequest drop_rows_by_prefix; + drop_rows_by_prefix.set_name(table.table_name()); + drop_rows_by_prefix.set_row_key_prefix(row_key1_prefix); + EXPECT_STATUS_OK(table_admin_->DropRowRange(drop_rows_by_prefix)); auto actual_cells = ReadRows(table, bigtable::Filter::PassAllFilter()); - CheckEqualUnordered(expected_cells, actual_cells); } -TEST_F(AdminIntegrationTest, DropAllRows) { +TEST_F(TableAdminIntegrationTest, DropAllRows) { auto table = GetTable(); // Create a vector of cell which will be inserted into bigtable @@ -133,19 +151,21 @@ TEST_F(AdminIntegrationTest, DropAllRows) { // Create records CreateCells(table, created_cells); // Delete all the records from a table - EXPECT_STATUS_OK(table_admin_->DropAllRows( - bigtable::testing::TableTestEnvironment::table_id())); + google::bigtable::admin::v2::DropRowRangeRequest drop_all_rows; + drop_all_rows.set_name(table.table_name()); + drop_all_rows.set_delete_all_data_from_table(true); + EXPECT_STATUS_OK(table_admin_->DropRowRange(drop_all_rows)); auto actual_cells = ReadRows(table, bigtable::Filter::PassAllFilter()); - ASSERT_TRUE(actual_cells.empty()); } /// @test Verify that `bigtable::TableAdmin` CRUD operations work as expected. -TEST_F(AdminIntegrationTest, CreateListGetDeleteTable) { +TEST_F(TableAdminIntegrationTest, CreateListGetDeleteTable) { using GC = bigtable::GcRule; auto const table_id = RandomTableId(); auto const table_name = bigtable::TableName(project_id(), instance_id(), table_id); + auto const instance_name = InstanceName(project_id(), instance_id()); // Create table config bigtable::TableConfig table_config( @@ -154,17 +174,28 @@ TEST_F(AdminIntegrationTest, CreateListGetDeleteTable) { {"a1000", "a2000", "b3000", "m5000"}); // Create table - ASSERT_STATUS_OK(table_admin_->CreateTable(table_id, table_config)); + google::bigtable::admin::v2::CreateTableRequest create_request = + std::move(table_config).as_proto(); + create_request.set_parent(instance_name); + create_request.set_table_id(table_id); + ASSERT_STATUS_OK(table_admin_->CreateTable(create_request)); bigtable::Table table(MakeDataConnection(), TableResource(project_id(), instance_id(), table_id)); // List tables - auto tables = table_admin_->ListTables(btadmin::Table::NAME_ONLY); - ASSERT_STATUS_OK(tables); - EXPECT_THAT(TableNames(*tables), Contains(table_name)); + google::bigtable::admin::v2::ListTablesRequest list_request; + list_request.set_parent(instance_name); + list_request.set_view(btadmin::Table::NAME_ONLY); + auto tables = table_admin_->ListTables(list_request); + auto table_list = TableNames(tables); + ASSERT_STATUS_OK(table_list); + EXPECT_THAT(*table_list, Contains(table_name)); // Get table - auto table_detailed = table_admin_->GetTable(table_id, btadmin::Table::FULL); + google::bigtable::admin::v2::GetTableRequest get_request; + get_request.set_name(table_name); + get_request.set_view(btadmin::Table::FULL); + auto table_detailed = table_admin_->GetTable(get_request); ASSERT_STATUS_OK(table_detailed); // Verify new table was created @@ -185,15 +216,20 @@ TEST_F(AdminIntegrationTest, CreateListGetDeleteTable) { EXPECT_EQ(1, count_matching_families(*table_detailed, "foo")); // Update table - std::vector column_modification_list = { - bigtable::ColumnFamilyModification::Create( - "newfam", GC::Intersection(GC::MaxAge(std::chrono::hours(7 * 24)), - GC::MaxNumVersions(1))), - bigtable::ColumnFamilyModification::Update("fam", GC::MaxNumVersions(2)), - bigtable::ColumnFamilyModification::Drop("foo")}; + std::vector< + google::bigtable::admin::v2::ModifyColumnFamiliesRequest::Modification> + column_modification_list = { + bigtable::ColumnFamilyModification::Create( + "newfam", GC::Intersection(GC::MaxAge(std::chrono::hours(7 * 24)), + GC::MaxNumVersions(1))) + .as_proto(), + bigtable::ColumnFamilyModification::Update("fam", + GC::MaxNumVersions(2)) + .as_proto(), + bigtable::ColumnFamilyModification::Drop("foo").as_proto()}; auto table_modified = - table_admin_->ModifyColumnFamilies(table_id, column_modification_list); + table_admin_->ModifyColumnFamilies(table_name, column_modification_list); ASSERT_STATUS_OK(table_modified); EXPECT_EQ(1, count_matching_families(*table_modified, "fam")); EXPECT_EQ(0, count_matching_families(*table_modified, "foo")); @@ -203,17 +239,18 @@ TEST_F(AdminIntegrationTest, CreateListGetDeleteTable) { EXPECT_EQ(2, gc.intersection().rules_size()); // Delete table - EXPECT_STATUS_OK(table_admin_->DeleteTable(table_id)); + EXPECT_STATUS_OK(table_admin_->DeleteTable(table_name)); // List to verify it is no longer there - tables = table_admin_->ListTables(btadmin::Table::NAME_ONLY); - ASSERT_STATUS_OK(tables); - EXPECT_THAT(TableNames(*tables), Not(Contains(table_name))); + tables = table_admin_->ListTables(list_request); + table_list = TableNames(tables); + ASSERT_STATUS_OK(table_list); + EXPECT_THAT(*table_list, Not(Contains(table_name))); } /// @test Verify that `bigtable::TableAdmin` WaitForConsistencyCheck works as /// expected. -TEST_F(AdminIntegrationTest, WaitForConsistencyCheck) { +TEST_F(TableAdminIntegrationTest, WaitForConsistencyCheck) { // WaitForConsistencyCheck() only makes sense on a replicated table, we need // to create an instance with at least 2 clusters to test it. auto const id = bigtable::testing::TableTestEnvironment::RandomInstanceId(); @@ -221,11 +258,13 @@ TEST_F(AdminIntegrationTest, WaitForConsistencyCheck) { // Create a bigtable::InstanceAdmin and a bigtable::TableAdmin to create the // new instance and the new table. - auto instance_admin_client = bigtable::MakeInstanceAdminClient(project_id()); - bigtable::InstanceAdmin instance_admin(instance_admin_client); - - auto admin_client = bigtable::MakeAdminClient(project_id()); - bigtable::TableAdmin table_admin(admin_client, id); + auto instance_admin = + std::make_unique( + bigtable_admin::MakeBigtableInstanceAdminConnection()); + auto table_admin_connection = + bigtable_admin::MakeBigtableTableAdminConnection(); + auto table_admin = std::make_unique( + table_admin_connection); // The instance configuration is involved, it needs two clusters, which must // be production clusters (and therefore have at least 3 nodes each), and @@ -243,7 +282,9 @@ TEST_F(AdminIntegrationTest, WaitForConsistencyCheck) { {{id + "-c1", cluster_config_1}, {id + "-c2", cluster_config_2}}); // Create the new instance. - auto instance = instance_admin.CreateInstance(config).get(); + auto create_request = config.as_proto(); + create_request.set_parent(Project(project_id()).FullName()); + auto instance = instance_admin->CreateInstance(create_request).get(); ASSERT_STATUS_OK(instance); // The table is going to be very simple, just one column family. @@ -252,7 +293,10 @@ TEST_F(AdminIntegrationTest, WaitForConsistencyCheck) { {{family, bigtable::GcRule::MaxNumVersions(10)}}, {}); // Create the new table. - auto table_created = table_admin.CreateTable(random_table_id, table_config); + auto request = std::move(table_config).as_proto(); + request.set_parent(InstanceName(project_id(), id)); + request.set_table_id(random_table_id); + auto table_created = table_admin->CreateTable(request); ASSERT_STATUS_OK(table_created); // We need to mutate the data in the table and then wait for those mutations @@ -273,24 +317,26 @@ TEST_F(AdminIntegrationTest, WaitForConsistencyCheck) { // Create a consistency token after modifying the table. auto consistency_token = - table_admin.GenerateConsistencyToken(random_table_id); + table_admin->GenerateConsistencyToken(table_created->name()); ASSERT_STATUS_OK(consistency_token); // Wait until all the mutations before the `consistency_token` have propagated // everywhere. - google::cloud::future> result = - table_admin.WaitForConsistency(random_table_id, *consistency_token); + google::cloud::future> + result = google::cloud::bigtable_admin::WaitForConsistency( + table_admin_connection, table_created->name(), + consistency_token->consistency_token()); auto is_consistent = result.get(); ASSERT_STATUS_OK(is_consistent); - EXPECT_EQ(bigtable::Consistency::kConsistent, *is_consistent); + EXPECT_EQ(bigtable_admin::Consistency::kConsistent, *is_consistent); // Cleanup the table and the instance. - EXPECT_STATUS_OK(table_admin.DeleteTable(random_table_id)); - EXPECT_STATUS_OK(instance_admin.DeleteInstance(id)); + EXPECT_STATUS_OK(table_admin->DeleteTable(table_created->name())); + EXPECT_STATUS_OK(instance_admin->DeleteInstance(instance->name())); } /// @test Verify rpc logging for `bigtable::TableAdmin` -TEST_F(AdminIntegrationTest, CreateListGetDeleteTableWithLogging) { +TEST_F(TableAdminIntegrationTest, CreateListGetDeleteTableWithLogging) { using GC = bigtable::GcRule; // In our ci builds, we set GOOGLE_CLOUD_CPP_ENABLE_TRACING to log our tests, // by default. We should unset this variable and create a fresh client in @@ -299,16 +345,16 @@ TEST_F(AdminIntegrationTest, CreateListGetDeleteTableWithLogging) { absl::nullopt}; testing_util::ScopedLog log; + auto const instance_name = + bigtable::InstanceName(project_id(), instance_id()); + auto const table_id = RandomTableId(); auto const table_name = bigtable::TableName(project_id(), instance_id(), table_id); - std::shared_ptr admin_client = - bigtable::MakeAdminClient( - bigtable::testing::TableTestEnvironment::project_id(), - Options{}.set({"rpc"})); - auto table_admin = std::make_unique( - admin_client, bigtable::testing::TableTestEnvironment::instance_id()); + auto table_admin = std::make_unique( + bigtable_admin::MakeBigtableTableAdminConnection( + Options{}.set({"rpc"}))); // Create table config bigtable::TableConfig table_config( @@ -317,17 +363,30 @@ TEST_F(AdminIntegrationTest, CreateListGetDeleteTableWithLogging) { {"a1000", "a2000", "b3000", "m5000"}); // Create table - ASSERT_STATUS_OK(table_admin->CreateTable(table_id, table_config)); + auto request = std::move(table_config).as_proto(); + request.set_parent(instance_name); + request.set_table_id(table_id); + ASSERT_STATUS_OK(table_admin->CreateTable(request)); bigtable::Table table(MakeDataConnection(), TableResource(project_id(), instance_id(), table_id)); // List tables - auto tables = table_admin->ListTables(btadmin::Table::NAME_ONLY); - ASSERT_STATUS_OK(tables); - EXPECT_THAT(TableNames(*tables), Contains(table_name)); + google::bigtable::admin::v2::ListTablesRequest list_request; + list_request.set_parent(instance_name); + list_request.set_view(btadmin::Table::NAME_ONLY); + auto tables = table_admin->ListTables(list_request); + std::vector table_list; + for (auto& t : tables) { + ASSERT_STATUS_OK(t); + table_list.push_back(*t); + } + EXPECT_THAT(TableNames(table_list), Contains(table_name)); // Get table - auto table_detailed = table_admin->GetTable(table_id, btadmin::Table::FULL); + google::bigtable::admin::v2::GetTableRequest get_request; + get_request.set_name(table_name); + get_request.set_view(btadmin::Table::FULL); + auto table_detailed = table_admin->GetTable(get_request); ASSERT_STATUS_OK(table_detailed); // Verify new table was created @@ -348,15 +407,20 @@ TEST_F(AdminIntegrationTest, CreateListGetDeleteTableWithLogging) { EXPECT_EQ(1, count_matching_families(*table_detailed, "foo")); // Update table - std::vector column_modification_list = { - bigtable::ColumnFamilyModification::Create( - "newfam", GC::Intersection(GC::MaxAge(std::chrono::hours(7 * 24)), - GC::MaxNumVersions(1))), - bigtable::ColumnFamilyModification::Update("fam", GC::MaxNumVersions(2)), - bigtable::ColumnFamilyModification::Drop("foo")}; + std::vector< + google::bigtable::admin::v2::ModifyColumnFamiliesRequest::Modification> + column_modification_list = { + bigtable::ColumnFamilyModification::Create( + "newfam", GC::Intersection(GC::MaxAge(std::chrono::hours(7 * 24)), + GC::MaxNumVersions(1))) + .as_proto(), + bigtable::ColumnFamilyModification::Update("fam", + GC::MaxNumVersions(2)) + .as_proto(), + bigtable::ColumnFamilyModification::Drop("foo").as_proto()}; auto table_modified = - table_admin->ModifyColumnFamilies(table_id, column_modification_list); + table_admin->ModifyColumnFamilies(table_name, column_modification_list); ASSERT_STATUS_OK(table_modified); EXPECT_EQ(1, count_matching_families(*table_modified, "fam")); EXPECT_EQ(0, count_matching_families(*table_modified, "foo")); @@ -366,12 +430,16 @@ TEST_F(AdminIntegrationTest, CreateListGetDeleteTableWithLogging) { EXPECT_EQ(2, gc.intersection().rules_size()); // Delete table - EXPECT_STATUS_OK(table_admin->DeleteTable(table_id)); + EXPECT_STATUS_OK(table_admin->DeleteTable(table_name)); // List to verify it is no longer there - tables = table_admin->ListTables(btadmin::Table::NAME_ONLY); - ASSERT_STATUS_OK(tables); - EXPECT_THAT(TableNames(*tables), Not(Contains(table_name))); + tables = table_admin->ListTables(list_request); + table_list.clear(); + for (auto& t : tables) { + ASSERT_STATUS_OK(t); + table_list.push_back(*t); + } + EXPECT_THAT(TableNames(table_list), Not(Contains(table_name))); auto const log_lines = log.ExtractLines(); EXPECT_THAT(log_lines, Contains(HasSubstr("CreateTable"))); @@ -381,9 +449,9 @@ TEST_F(AdminIntegrationTest, CreateListGetDeleteTableWithLogging) { EXPECT_THAT(log_lines, Contains(HasSubstr("DeleteTable"))); // Verify that a normal client does not log. - auto no_logging_client = - TableAdmin(MakeAdminClient(project_id()), instance_id()); - (void)no_logging_client.ListTables(btadmin::Table::NAME_ONLY); + auto no_logging_client = bigtable_admin::BigtableTableAdminClient( + bigtable_admin::MakeBigtableTableAdminConnection()); + (void)no_logging_client.ListTables(list_request); EXPECT_THAT(log.ExtractLines(), Not(Contains(HasSubstr("ListTables")))); } diff --git a/google/cloud/bigtable/wait_for_consistency.cc b/google/cloud/bigtable/wait_for_consistency.cc index 1b1d235e80c37..5cd75ee63b7d2 100644 --- a/google/cloud/bigtable/wait_for_consistency.cc +++ b/google/cloud/bigtable/wait_for_consistency.cc @@ -13,15 +13,43 @@ // limitations under the License. #include "google/cloud/bigtable/wait_for_consistency.h" +#include "google/cloud/bigtable/admin/bigtable_table_admin_client.h" #include "google/cloud/bigtable/admin/bigtable_table_admin_options.h" #include "google/cloud/bigtable/admin/internal/bigtable_table_admin_option_defaults.h" +#include "google/cloud/bigtable/resource_names.h" #include "google/cloud/internal/make_status.h" +#include "google/bigtable/admin/v2/bigtable_table_admin.grpc.pb.h" #include namespace google { namespace cloud { namespace bigtable_admin { GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN + +google::cloud::future> WaitForConsistency( + std::shared_ptr const& connection, + std::string const& table_id, std::string const& consistency_token, + Options options) { + auto cq = bigtable_admin_internal::completion_queue(*connection); + if (!cq.ok()) return make_ready_future(StatusOr(cq.status())); + + // We avoid lifetime issues due to ownership cycles, by holding the + // `BackgroundThreads` which run the `CompletionQueue` outside of the + // operation, in this class. If the `BackgroundThreads` running the + // `CompletionQueue` were instead owned by the Connection, we would have an + // ownership cycle. We have made this mistake before. See #7740 for more + // details. + auto client = bigtable_admin::BigtableTableAdminClient(connection); + return bigtable_admin::AsyncWaitForConsistency( + *std::move(cq), std::move(client), table_id, consistency_token, + std::move(options)) + .then([](future f) -> StatusOr { + auto s = f.get(); + if (!s.ok()) return s; + return Consistency::kConsistent; + }); +} + namespace { // This class borrows heavily from `google::cloud::internal::AsyncRetryLoop` @@ -52,7 +80,8 @@ class AsyncWaitForConsistencyImpl } private: - using RespType = StatusOr; + using RespType = + StatusOr; using TimerResult = StatusOr; struct State { @@ -152,7 +181,7 @@ class AsyncWaitForConsistencyImpl } CompletionQueue cq_; - bigtable::admin::v2::CheckConsistencyRequest request_; + google::bigtable::admin::v2::CheckConsistencyRequest request_; BigtableTableAdminClient client_; Options options_; std::shared_ptr polling_policy_; diff --git a/google/cloud/bigtable/wait_for_consistency.h b/google/cloud/bigtable/wait_for_consistency.h index 3deb77fa7c05d..2df9765b1372b 100644 --- a/google/cloud/bigtable/wait_for_consistency.h +++ b/google/cloud/bigtable/wait_for_consistency.h @@ -23,6 +23,39 @@ namespace cloud { namespace bigtable_admin { GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN +enum class Consistency { + /// Some of the mutations created before the consistency token have not been + /// received by all the table replicas. + kInconsistent, + /// All mutations created before the consistency token have been received by + /// all the table replicas. + kConsistent, +}; + +/** + * Checks consistency of a table with multiple calls using a background thread + * from the provided connection. + * + * This function polls the service until the table is Consistent, the polling + * policies are exhausted, or an error occurs. + * + * @param connection the connection to the Bigtable admin service. + * @param table_name the full name of the table for which we want to check + * consistency ("projects//instances//tables/"). + * @param consistency_token the consistency token of the table. + * @return the consistency status for the table. + * + * @par Idempotency + * This operation is read-only and therefore it is always idempotent. + * + * @par Example + * @snippet table_admin_snippets.cc wait for consistency check + */ +google::cloud::future> WaitForConsistency( + std::shared_ptr const& connection, + std::string const& table_name, std::string const& consistency_token, + Options options = {}); + /** * Polls until a table is consistent, or until the polling policy has expired. * From 6c8800900f8a7522e0c8a1591048f69b9d256b35 Mon Sep 17 00:00:00 2001 From: Scott Hart Date: Wed, 28 Jan 2026 11:49:37 -0500 Subject: [PATCH 2/8] update async retry loop to take predicate --- google/cloud/internal/async_retry_loop.h | 66 ++++++++++++++++-------- 1 file changed, 44 insertions(+), 22 deletions(-) diff --git a/google/cloud/internal/async_retry_loop.h b/google/cloud/internal/async_retry_loop.h index 9866947c5b4d3..0e052dc22e654 100644 --- a/google/cloud/internal/async_retry_loop.h +++ b/google/cloud/internal/async_retry_loop.h @@ -170,16 +170,23 @@ struct FutureValueType> { * functions. If the value is visible, the retry loop will stop on the next * callback and/or before the next request or timer is issued. */ -template +template < + typename Functor, typename Request, typename RetryPolicyType, + typename ReturnType = google::cloud::internal::invoke_result_t< + Functor, google::cloud::CompletionQueue&, + std::shared_ptr, ImmutableOptions, Request const&>> class AsyncRetryLoopImpl : public std::enable_shared_from_this< AsyncRetryLoopImpl> { public: - AsyncRetryLoopImpl(std::unique_ptr retry_policy, - std::unique_ptr backoff_policy, - Idempotency idempotency, google::cloud::CompletionQueue cq, - Functor&& functor, ImmutableOptions options, - Request request, char const* location) + AsyncRetryLoopImpl( + std::unique_ptr retry_policy, + std::unique_ptr backoff_policy, Idempotency idempotency, + google::cloud::CompletionQueue cq, Functor&& functor, + ImmutableOptions options, Request request, char const* location, + std::function< + bool(typename FutureValueType::value_type const&)> + attempt_predicate = {}) : retry_policy_(std::move(retry_policy)), backoff_policy_(std::move(backoff_policy)), idempotency_(idempotency), @@ -188,11 +195,13 @@ class AsyncRetryLoopImpl functor_(std::forward(functor)), request_(std::move(request)), location_(location), - call_context_(std::move(options)) {} + call_context_(std::move(options)), + attempt_predicate_(std::move(attempt_predicate)) {} - using ReturnType = ::google::cloud::internal::invoke_result_t< - Functor, google::cloud::CompletionQueue&, - std::shared_ptr, ImmutableOptions, Request const&>; + // using ReturnType = ::google::cloud::internal::invoke_result_t< + // Functor, google::cloud::CompletionQueue&, + // std::shared_ptr, ImmutableOptions, Request + // const&>; using T = typename FutureValueType::value_type; future Start() { @@ -256,6 +265,11 @@ class AsyncRetryLoopImpl } void OnAttempt(T result) { + if (attempt_predicate_) { + if (result.ok() && attempt_predicate_(result)) { + return SetDone(std::move(result)); + } + } // A successful attempt, set the value and finish the loop. if (result.ok()) return SetDone(std::move(result)); // Some kind of failure, first verify that it is retryable. @@ -325,6 +339,8 @@ class AsyncRetryLoopImpl CallContext call_context_; Status last_status_; promise result_; + std::function::value_type const&)> + attempt_predicate_; // Only the following variables require synchronization, as they coordinate // the work between the retry loop (which would be lock-free) and the cancel @@ -339,17 +355,23 @@ class AsyncRetryLoopImpl /** * Create the right AsyncRetryLoopImpl object and start the retry loop on it. */ -template , - ImmutableOptions, Request const&>::value, - int> = 0> -auto AsyncRetryLoop(std::unique_ptr retry_policy, - std::unique_ptr backoff_policy, - Idempotency idempotency, google::cloud::CompletionQueue cq, - Functor&& functor, ImmutableOptions options, - Request request, char const* location) +template < + typename Functor, typename Request, typename RetryPolicyType, + std::enable_if_t, ImmutableOptions, + Request const&>::value, + int> = 0, + typename ReturnType = google::cloud::internal::invoke_result_t< + Functor, google::cloud::CompletionQueue&, + std::shared_ptr, ImmutableOptions, Request const&>> +auto AsyncRetryLoop( + std::unique_ptr retry_policy, + std::unique_ptr backoff_policy, Idempotency idempotency, + google::cloud::CompletionQueue cq, Functor&& functor, + ImmutableOptions options, Request request, char const* location, + std::function::value_type const&)> + attempt_predicate = {}) -> google::cloud::internal::invoke_result_t< Functor, google::cloud::CompletionQueue&, std::shared_ptr, ImmutableOptions, @@ -358,7 +380,7 @@ auto AsyncRetryLoop(std::unique_ptr retry_policy, std::make_shared>( std::move(retry_policy), std::move(backoff_policy), idempotency, std::move(cq), std::forward(functor), options, - std::move(request), location); + std::move(request), location, std::move(attempt_predicate)); return loop->Start(); } From dc126b9a9059be310e59ed31a972434111a357dd Mon Sep 17 00:00:00 2001 From: Scott Hart Date: Wed, 28 Jan 2026 12:57:26 -0500 Subject: [PATCH 3/8] custom wait function --- .../admin/bigtable_table_admin_client.cc | 8 ++++++ .../admin/bigtable_table_admin_client.h | 4 +++ .../admin/bigtable_table_admin_connection.cc | 7 +++++ .../admin/bigtable_table_admin_connection.h | 3 +++ .../bigtable_table_admin_connection_impl.cc | 26 +++++++++++++++++++ .../bigtable_table_admin_connection_impl.h | 3 +++ .../bigtable/examples/table_admin_snippets.cc | 11 +++++--- .../tests/table_admin_integration_test.cc | 17 +++++++----- 8 files changed, 70 insertions(+), 9 deletions(-) diff --git a/google/cloud/bigtable/admin/bigtable_table_admin_client.cc b/google/cloud/bigtable/admin/bigtable_table_admin_client.cc index a30ce9aac2bca..cf2e8e61fda56 100644 --- a/google/cloud/bigtable/admin/bigtable_table_admin_client.cc +++ b/google/cloud/bigtable/admin/bigtable_table_admin_client.cc @@ -821,6 +821,14 @@ BigtableTableAdminClient::AsyncCheckConsistency( return connection_->AsyncCheckConsistency(request); } +future> + BigtableTableAdminClient::WaitForConsistency(google::bigtable::admin::v2::CheckConsistencyRequest const& request, + Options opts) { + internal::OptionsSpan span(internal::MergeOptions(std::move(opts), options_)); + return connection_->WaitForConsistency(request); +} + + GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END } // namespace bigtable_admin } // namespace cloud diff --git a/google/cloud/bigtable/admin/bigtable_table_admin_client.h b/google/cloud/bigtable/admin/bigtable_table_admin_client.h index b9049768b5d7e..5a86e28c8b667 100644 --- a/google/cloud/bigtable/admin/bigtable_table_admin_client.h +++ b/google/cloud/bigtable/admin/bigtable_table_admin_client.h @@ -2581,6 +2581,10 @@ class BigtableTableAdminClient { google::bigtable::admin::v2::CheckConsistencyRequest const& request, Options opts = {}); +future> + WaitForConsistency(google::bigtable::admin::v2::CheckConsistencyRequest const& request, + Options opts = {}); + private: std::shared_ptr connection_; Options options_; diff --git a/google/cloud/bigtable/admin/bigtable_table_admin_connection.cc b/google/cloud/bigtable/admin/bigtable_table_admin_connection.cc index 26613c3f155e6..fa30963cedcba 100644 --- a/google/cloud/bigtable/admin/bigtable_table_admin_connection.cc +++ b/google/cloud/bigtable/admin/bigtable_table_admin_connection.cc @@ -382,6 +382,13 @@ BigtableTableAdminConnection::AsyncCheckConsistency( Status(StatusCode::kUnimplemented, "not implemented")); } +future> + BigtableTableAdminConnection::WaitForConsistency(google::bigtable::admin::v2::CheckConsistencyRequest const& request) { + return google::cloud::make_ready_future< + StatusOr>( + Status(StatusCode::kUnimplemented, "not implemented")); +} + StatusOr BigtableTableAdminConnection::completion_queue() const { return Status(StatusCode::kUnimplemented, "not implemented"); diff --git a/google/cloud/bigtable/admin/bigtable_table_admin_connection.h b/google/cloud/bigtable/admin/bigtable_table_admin_connection.h index e7cc3987491a4..7af59f9ddf735 100644 --- a/google/cloud/bigtable/admin/bigtable_table_admin_connection.h +++ b/google/cloud/bigtable/admin/bigtable_table_admin_connection.h @@ -382,6 +382,9 @@ class BigtableTableAdminConnection { AsyncCheckConsistency( google::bigtable::admin::v2::CheckConsistencyRequest const& request); + virtual future> + WaitForConsistency(google::bigtable::admin::v2::CheckConsistencyRequest const& request); + protected: friend StatusOr bigtable_admin_internal::completion_queue( BigtableTableAdminConnection const& conn); diff --git a/google/cloud/bigtable/admin/internal/bigtable_table_admin_connection_impl.cc b/google/cloud/bigtable/admin/internal/bigtable_table_admin_connection_impl.cc index c2cc66d3cff53..1c86d7c5aa5bb 100644 --- a/google/cloud/bigtable/admin/internal/bigtable_table_admin_connection_impl.cc +++ b/google/cloud/bigtable/admin/internal/bigtable_table_admin_connection_impl.cc @@ -1298,6 +1298,32 @@ BigtableTableAdminConnectionImpl::AsyncCheckConsistency( std::move(current), std::move(request_copy), __func__); } +future> + BigtableTableAdminConnectionImpl::WaitForConsistency( + google::bigtable::admin::v2::CheckConsistencyRequest const& request) { + auto current = google::cloud::internal::SaveCurrentOptions(); + auto request_copy = request; + auto const idempotent = + idempotency_policy(*current)->CheckConsistency(request_copy); + auto retry = retry_policy(*current); + auto backoff = backoff_policy(*current); + auto attempt_predicate = []( + StatusOr const& r) { + return r.ok() && r->consistent(); + }; + return google::cloud::internal::AsyncRetryLoop( + std::move(retry), std::move(backoff), idempotent, background_->cq(), + [stub = stub_]( + CompletionQueue& cq, std::shared_ptr context, + google::cloud::internal::ImmutableOptions options, + google::bigtable::admin::v2::CheckConsistencyRequest const& request) { + return stub->AsyncCheckConsistency(cq, std::move(context), + std::move(options), request); + }, + std::move(current), std::move(request_copy), __func__, + std::move(attempt_predicate)); +} + StatusOr BigtableTableAdminConnectionImpl::completion_queue() const { return background_->cq(); diff --git a/google/cloud/bigtable/admin/internal/bigtable_table_admin_connection_impl.h b/google/cloud/bigtable/admin/internal/bigtable_table_admin_connection_impl.h index 0fa8d168eabb1..0d7d721d3fb7a 100644 --- a/google/cloud/bigtable/admin/internal/bigtable_table_admin_connection_impl.h +++ b/google/cloud/bigtable/admin/internal/bigtable_table_admin_connection_impl.h @@ -234,6 +234,9 @@ class BigtableTableAdminConnectionImpl google::bigtable::admin::v2::CheckConsistencyRequest const& request) override; + future> + WaitForConsistency(google::bigtable::admin::v2::CheckConsistencyRequest const& request) override; + private: std::unique_ptr background_; std::shared_ptr stub_; diff --git a/google/cloud/bigtable/examples/table_admin_snippets.cc b/google/cloud/bigtable/examples/table_admin_snippets.cc index 18d206f55cab1..bdfff208ca265 100644 --- a/google/cloud/bigtable/examples/table_admin_snippets.cc +++ b/google/cloud/bigtable/examples/table_admin_snippets.cc @@ -643,9 +643,14 @@ void WaitForConsistencyCheck( throw std::move(consistency_token).status(); } auto token = consistency_token->consistency_token(); - auto consistency_future = - cbta::WaitForConsistency(connection, table_name, token); - StatusOr consistency = consistency_future.get(); +// auto consistency_future = +// cbta::WaitForConsistency(connection, table_name, token); + + google::bigtable::admin::v2::CheckConsistencyRequest wait_request; + wait_request.set_name(table_name); + wait_request.set_consistency_token(token); + auto consistency_future = client.WaitForConsistency(wait_request); + auto consistency = consistency_future.get(); if (!consistency) throw std::runtime_error(consistency.status().message()); std::cout << "Table is consistent with token " << token << "\n"; } diff --git a/google/cloud/bigtable/tests/table_admin_integration_test.cc b/google/cloud/bigtable/tests/table_admin_integration_test.cc index c51760adefdc3..ae7fc702762e9 100644 --- a/google/cloud/bigtable/tests/table_admin_integration_test.cc +++ b/google/cloud/bigtable/tests/table_admin_integration_test.cc @@ -322,13 +322,18 @@ TEST_F(TableAdminIntegrationTest, WaitForConsistencyCheck) { // Wait until all the mutations before the `consistency_token` have propagated // everywhere. - google::cloud::future> - result = google::cloud::bigtable_admin::WaitForConsistency( - table_admin_connection, table_created->name(), - consistency_token->consistency_token()); - auto is_consistent = result.get(); +// google::cloud::future> +// result = google::cloud::bigtable_admin::WaitForConsistency( +// table_admin_connection, table_created->name(), +// consistency_token->consistency_token()); + + google::bigtable::admin::v2::CheckConsistencyRequest wait_request; + wait_request.set_name(table_created->name()); + wait_request.set_consistency_token(consistency_token->consistency_token()); + future> result = table_admin->WaitForConsistency(wait_request); + StatusOr is_consistent = result.get(); ASSERT_STATUS_OK(is_consistent); - EXPECT_EQ(bigtable_admin::Consistency::kConsistent, *is_consistent); + EXPECT_TRUE(is_consistent->consistent()); // Cleanup the table and the instance. EXPECT_STATUS_OK(table_admin->DeleteTable(table_created->name())); From bc87edaf992837783c94119d794bd1af68d22f2d Mon Sep 17 00:00:00 2001 From: Scott Hart Date: Wed, 28 Jan 2026 14:19:54 -0500 Subject: [PATCH 4/8] wait consistency wip --- .../bigtable/admin/bigtable_table_admin_client.cc | 6 +++--- .../bigtable/admin/bigtable_table_admin_client.h | 7 ++++--- .../admin/bigtable_table_admin_connection.cc | 5 +++-- .../admin/bigtable_table_admin_connection.h | 6 ++++-- .../bigtable_table_admin_connection_impl.cc | 11 +++++------ .../bigtable_table_admin_connection_impl.h | 3 ++- .../bigtable/examples/table_admin_snippets.cc | 4 ++-- .../bigtable/tests/table_admin_integration_test.cc | 14 ++++++++------ 8 files changed, 31 insertions(+), 25 deletions(-) diff --git a/google/cloud/bigtable/admin/bigtable_table_admin_client.cc b/google/cloud/bigtable/admin/bigtable_table_admin_client.cc index cf2e8e61fda56..347aa10bba977 100644 --- a/google/cloud/bigtable/admin/bigtable_table_admin_client.cc +++ b/google/cloud/bigtable/admin/bigtable_table_admin_client.cc @@ -822,13 +822,13 @@ BigtableTableAdminClient::AsyncCheckConsistency( } future> - BigtableTableAdminClient::WaitForConsistency(google::bigtable::admin::v2::CheckConsistencyRequest const& request, - Options opts) { +BigtableTableAdminClient::WaitForConsistency( + google::bigtable::admin::v2::CheckConsistencyRequest const& request, + Options opts) { internal::OptionsSpan span(internal::MergeOptions(std::move(opts), options_)); return connection_->WaitForConsistency(request); } - GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END } // namespace bigtable_admin } // namespace cloud diff --git a/google/cloud/bigtable/admin/bigtable_table_admin_client.h b/google/cloud/bigtable/admin/bigtable_table_admin_client.h index 5a86e28c8b667..07ceb1ae753e2 100644 --- a/google/cloud/bigtable/admin/bigtable_table_admin_client.h +++ b/google/cloud/bigtable/admin/bigtable_table_admin_client.h @@ -2581,9 +2581,10 @@ class BigtableTableAdminClient { google::bigtable::admin::v2::CheckConsistencyRequest const& request, Options opts = {}); -future> - WaitForConsistency(google::bigtable::admin::v2::CheckConsistencyRequest const& request, - Options opts = {}); + future> + WaitForConsistency( + google::bigtable::admin::v2::CheckConsistencyRequest const& request, + Options opts = {}); private: std::shared_ptr connection_; diff --git a/google/cloud/bigtable/admin/bigtable_table_admin_connection.cc b/google/cloud/bigtable/admin/bigtable_table_admin_connection.cc index fa30963cedcba..cb74e36231ae5 100644 --- a/google/cloud/bigtable/admin/bigtable_table_admin_connection.cc +++ b/google/cloud/bigtable/admin/bigtable_table_admin_connection.cc @@ -383,8 +383,9 @@ BigtableTableAdminConnection::AsyncCheckConsistency( } future> - BigtableTableAdminConnection::WaitForConsistency(google::bigtable::admin::v2::CheckConsistencyRequest const& request) { - return google::cloud::make_ready_future< +BigtableTableAdminConnection::WaitForConsistency( + google::bigtable::admin::v2::CheckConsistencyRequest const&) { + return google::cloud::make_ready_future< StatusOr>( Status(StatusCode::kUnimplemented, "not implemented")); } diff --git a/google/cloud/bigtable/admin/bigtable_table_admin_connection.h b/google/cloud/bigtable/admin/bigtable_table_admin_connection.h index 7af59f9ddf735..2f1a12f6d4718 100644 --- a/google/cloud/bigtable/admin/bigtable_table_admin_connection.h +++ b/google/cloud/bigtable/admin/bigtable_table_admin_connection.h @@ -382,8 +382,10 @@ class BigtableTableAdminConnection { AsyncCheckConsistency( google::bigtable::admin::v2::CheckConsistencyRequest const& request); - virtual future> - WaitForConsistency(google::bigtable::admin::v2::CheckConsistencyRequest const& request); + virtual future< + StatusOr> + WaitForConsistency( + google::bigtable::admin::v2::CheckConsistencyRequest const& request); protected: friend StatusOr bigtable_admin_internal::completion_queue( diff --git a/google/cloud/bigtable/admin/internal/bigtable_table_admin_connection_impl.cc b/google/cloud/bigtable/admin/internal/bigtable_table_admin_connection_impl.cc index 1c86d7c5aa5bb..a5e8bc6c4b86a 100644 --- a/google/cloud/bigtable/admin/internal/bigtable_table_admin_connection_impl.cc +++ b/google/cloud/bigtable/admin/internal/bigtable_table_admin_connection_impl.cc @@ -1299,18 +1299,17 @@ BigtableTableAdminConnectionImpl::AsyncCheckConsistency( } future> - BigtableTableAdminConnectionImpl::WaitForConsistency( +BigtableTableAdminConnectionImpl::WaitForConsistency( google::bigtable::admin::v2::CheckConsistencyRequest const& request) { - auto current = google::cloud::internal::SaveCurrentOptions(); + auto current = google::cloud::internal::SaveCurrentOptions(); auto request_copy = request; auto const idempotent = idempotency_policy(*current)->CheckConsistency(request_copy); auto retry = retry_policy(*current); auto backoff = backoff_policy(*current); - auto attempt_predicate = []( - StatusOr const& r) { - return r.ok() && r->consistent(); - }; + auto attempt_predicate = + [](StatusOr const& + r) { return r.ok() && r->consistent(); }; return google::cloud::internal::AsyncRetryLoop( std::move(retry), std::move(backoff), idempotent, background_->cq(), [stub = stub_]( diff --git a/google/cloud/bigtable/admin/internal/bigtable_table_admin_connection_impl.h b/google/cloud/bigtable/admin/internal/bigtable_table_admin_connection_impl.h index 0d7d721d3fb7a..e9c8a4a80a6f6 100644 --- a/google/cloud/bigtable/admin/internal/bigtable_table_admin_connection_impl.h +++ b/google/cloud/bigtable/admin/internal/bigtable_table_admin_connection_impl.h @@ -235,7 +235,8 @@ class BigtableTableAdminConnectionImpl override; future> - WaitForConsistency(google::bigtable::admin::v2::CheckConsistencyRequest const& request) override; + WaitForConsistency(google::bigtable::admin::v2::CheckConsistencyRequest const& + request) override; private: std::unique_ptr background_; diff --git a/google/cloud/bigtable/examples/table_admin_snippets.cc b/google/cloud/bigtable/examples/table_admin_snippets.cc index bdfff208ca265..062f73ad9ff01 100644 --- a/google/cloud/bigtable/examples/table_admin_snippets.cc +++ b/google/cloud/bigtable/examples/table_admin_snippets.cc @@ -643,8 +643,8 @@ void WaitForConsistencyCheck( throw std::move(consistency_token).status(); } auto token = consistency_token->consistency_token(); -// auto consistency_future = -// cbta::WaitForConsistency(connection, table_name, token); + // auto consistency_future = + // cbta::WaitForConsistency(connection, table_name, token); google::bigtable::admin::v2::CheckConsistencyRequest wait_request; wait_request.set_name(table_name); diff --git a/google/cloud/bigtable/tests/table_admin_integration_test.cc b/google/cloud/bigtable/tests/table_admin_integration_test.cc index ae7fc702762e9..61164f4c060d3 100644 --- a/google/cloud/bigtable/tests/table_admin_integration_test.cc +++ b/google/cloud/bigtable/tests/table_admin_integration_test.cc @@ -322,16 +322,18 @@ TEST_F(TableAdminIntegrationTest, WaitForConsistencyCheck) { // Wait until all the mutations before the `consistency_token` have propagated // everywhere. -// google::cloud::future> -// result = google::cloud::bigtable_admin::WaitForConsistency( -// table_admin_connection, table_created->name(), -// consistency_token->consistency_token()); + // google::cloud::future> + // result = google::cloud::bigtable_admin::WaitForConsistency( + // table_admin_connection, table_created->name(), + // consistency_token->consistency_token()); google::bigtable::admin::v2::CheckConsistencyRequest wait_request; wait_request.set_name(table_created->name()); wait_request.set_consistency_token(consistency_token->consistency_token()); - future> result = table_admin->WaitForConsistency(wait_request); - StatusOr is_consistent = result.get(); + future> + result = table_admin->WaitForConsistency(wait_request); + StatusOr + is_consistent = result.get(); ASSERT_STATUS_OK(is_consistent); EXPECT_TRUE(is_consistent->consistent()); From 2426e4e3eb03320895ad799d0c0e6f00a0218d15 Mon Sep 17 00:00:00 2001 From: Scott Hart Date: Wed, 28 Jan 2026 16:19:57 -0500 Subject: [PATCH 5/8] add bespoke cc file --- google/cloud/bigtable/CMakeLists.txt | 1 + .../bigtable_table_admin_connection_impl.cc | 25 ------ ...ble_table_admin_connection_impl_bespoke.cc | 82 +++++++++++++++++++ .../bigtable/google_cloud_cpp_bigtable.bzl | 1 + 4 files changed, 84 insertions(+), 25 deletions(-) create mode 100644 google/cloud/bigtable/admin/internal/bigtable_table_admin_connection_impl_bespoke.cc diff --git a/google/cloud/bigtable/CMakeLists.txt b/google/cloud/bigtable/CMakeLists.txt index eb224a2e00832..67d32ef4ed3cd 100644 --- a/google/cloud/bigtable/CMakeLists.txt +++ b/google/cloud/bigtable/CMakeLists.txt @@ -89,6 +89,7 @@ add_library( admin/internal/bigtable_table_admin_auth_decorator.h admin/internal/bigtable_table_admin_connection_impl.cc admin/internal/bigtable_table_admin_connection_impl.h + admin/internal/bigtable_table_admin_connection_impl_bespoke.cc admin/internal/bigtable_table_admin_logging_decorator.cc admin/internal/bigtable_table_admin_logging_decorator.h admin/internal/bigtable_table_admin_metadata_decorator.cc diff --git a/google/cloud/bigtable/admin/internal/bigtable_table_admin_connection_impl.cc b/google/cloud/bigtable/admin/internal/bigtable_table_admin_connection_impl.cc index a5e8bc6c4b86a..c2cc66d3cff53 100644 --- a/google/cloud/bigtable/admin/internal/bigtable_table_admin_connection_impl.cc +++ b/google/cloud/bigtable/admin/internal/bigtable_table_admin_connection_impl.cc @@ -1298,31 +1298,6 @@ BigtableTableAdminConnectionImpl::AsyncCheckConsistency( std::move(current), std::move(request_copy), __func__); } -future> -BigtableTableAdminConnectionImpl::WaitForConsistency( - google::bigtable::admin::v2::CheckConsistencyRequest const& request) { - auto current = google::cloud::internal::SaveCurrentOptions(); - auto request_copy = request; - auto const idempotent = - idempotency_policy(*current)->CheckConsistency(request_copy); - auto retry = retry_policy(*current); - auto backoff = backoff_policy(*current); - auto attempt_predicate = - [](StatusOr const& - r) { return r.ok() && r->consistent(); }; - return google::cloud::internal::AsyncRetryLoop( - std::move(retry), std::move(backoff), idempotent, background_->cq(), - [stub = stub_]( - CompletionQueue& cq, std::shared_ptr context, - google::cloud::internal::ImmutableOptions options, - google::bigtable::admin::v2::CheckConsistencyRequest const& request) { - return stub->AsyncCheckConsistency(cq, std::move(context), - std::move(options), request); - }, - std::move(current), std::move(request_copy), __func__, - std::move(attempt_predicate)); -} - StatusOr BigtableTableAdminConnectionImpl::completion_queue() const { return background_->cq(); diff --git a/google/cloud/bigtable/admin/internal/bigtable_table_admin_connection_impl_bespoke.cc b/google/cloud/bigtable/admin/internal/bigtable_table_admin_connection_impl_bespoke.cc new file mode 100644 index 0000000000000..43b364397c734 --- /dev/null +++ b/google/cloud/bigtable/admin/internal/bigtable_table_admin_connection_impl_bespoke.cc @@ -0,0 +1,82 @@ +// 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 +// +// https://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. + +#include "google/cloud/bigtable/admin/internal/bigtable_table_admin_connection_impl.h" +#include "google/cloud/bigtable/admin/internal/bigtable_table_admin_option_defaults.h" +#include "google/cloud/background_threads.h" +#include "google/cloud/common_options.h" +#include "google/cloud/grpc_options.h" +#include "google/cloud/internal/async_long_running_operation.h" +#include "google/cloud/internal/async_retry_loop.h" +#include "google/cloud/internal/pagination_range.h" +#include "google/cloud/internal/retry_loop.h" +#include +#include + +namespace google { +namespace cloud { +namespace bigtable_admin_internal { +GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN +namespace { + +std::unique_ptr retry_policy( + Options const& options) { + return options.get() + ->clone(); +} + +std::unique_ptr backoff_policy(Options const& options) { + return options.get() + ->clone(); +} + +std::unique_ptr +idempotency_policy(Options const& options) { + return options + .get< + bigtable_admin::BigtableTableAdminConnectionIdempotencyPolicyOption>() + ->clone(); +} + +} // namespace + +future> +BigtableTableAdminConnectionImpl::WaitForConsistency( + google::bigtable::admin::v2::CheckConsistencyRequest const& request) { + auto current = google::cloud::internal::SaveCurrentOptions(); + auto request_copy = request; + auto const idempotent = + idempotency_policy(*current)->CheckConsistency(request_copy); + auto retry = retry_policy(*current); + auto backoff = backoff_policy(*current); + auto attempt_predicate = + [](StatusOr const& + r) { return r.ok() && r->consistent(); }; + return google::cloud::internal::AsyncRetryLoop( + std::move(retry), std::move(backoff), idempotent, background_->cq(), + [stub = stub_]( + CompletionQueue& cq, std::shared_ptr context, + google::cloud::internal::ImmutableOptions options, + google::bigtable::admin::v2::CheckConsistencyRequest const& request) { + return stub->AsyncCheckConsistency(cq, std::move(context), + std::move(options), request); + }, + std::move(current), std::move(request_copy), __func__, + std::move(attempt_predicate)); +} + +GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END +} // namespace bigtable_admin_internal +} // namespace cloud +} // namespace google diff --git a/google/cloud/bigtable/google_cloud_cpp_bigtable.bzl b/google/cloud/bigtable/google_cloud_cpp_bigtable.bzl index 3ff61adedaea1..3ee092bd083a4 100644 --- a/google/cloud/bigtable/google_cloud_cpp_bigtable.bzl +++ b/google/cloud/bigtable/google_cloud_cpp_bigtable.bzl @@ -159,6 +159,7 @@ google_cloud_cpp_bigtable_srcs = [ "admin/internal/bigtable_instance_admin_tracing_stub.cc", "admin/internal/bigtable_table_admin_auth_decorator.cc", "admin/internal/bigtable_table_admin_connection_impl.cc", + "admin/internal/bigtable_table_admin_connection_impl_bespoke.cc", "admin/internal/bigtable_table_admin_logging_decorator.cc", "admin/internal/bigtable_table_admin_metadata_decorator.cc", "admin/internal/bigtable_table_admin_option_defaults.cc", From 69169b69aa21dea1fa31c92ab4b726ea84a8d933 Mon Sep 17 00:00:00 2001 From: Scott Hart Date: Wed, 28 Jan 2026 19:36:54 -0500 Subject: [PATCH 6/8] generator kludge --- generator/generator_config.proto | 13 +++-- generator/generator_config.textproto | 7 ++- generator/internal/client_generator.cc | 20 +++++++ generator/internal/codegen_utils.cc | 6 +++ generator/internal/connection_generator.cc | 53 +++++++++---------- .../internal/connection_impl_generator.cc | 33 ++++-------- generator/internal/service_code_generator.cc | 22 ++++++-- generator/internal/service_code_generator.h | 8 ++- generator/standalone_main.cc | 15 ++++-- 9 files changed, 107 insertions(+), 70 deletions(-) diff --git a/generator/generator_config.proto b/generator/generator_config.proto index 7743c2e80e90f..ccfda6028c6ca 100644 --- a/generator/generator_config.proto +++ b/generator/generator_config.proto @@ -168,11 +168,14 @@ message ServiceConfiguration { // generated. bool omit_streaming_updater = 29; - // In rare cases, specifically bigtable::WaitForConsistency, the - // CompletionQueue from the BackgroundThreads owned by the Connection is - // needed elsewhere. This emits a protected accessor and friend function for - // that purpose. - bool emit_completion_queue_accessor = 30; + message BespokeMethod { + string client_comments = 1; + string name = 2; + string return_type = 3; + string parameters = 4; + } + + repeated BespokeMethod bespoke_methods = 30; } message DiscoveryDocumentDefinedProduct { diff --git a/generator/generator_config.textproto b/generator/generator_config.textproto index 380d664e48846..409a353df13ee 100644 --- a/generator/generator_config.textproto +++ b/generator/generator_config.textproto @@ -588,7 +588,12 @@ service { {rpc_name: "BigtableTableAdmin.CheckConsistency", idempotency: IDEMPOTENT} ] omit_repo_metadata: true - emit_completion_queue_accessor: true + bespoke_methods : [ + { + client_comments: "Polls until the table is consistent or until the retry policy has expired.", + name: "WaitForConsistency", + return_type: "future>", + parameters: "(google::bigtable::admin::v2::CheckConsistencyRequest const& request, Options opts = {})"}] } # Billing diff --git a/generator/internal/client_generator.cc b/generator/internal/client_generator.cc index 2e81d9431f5a6..2acfc6d584676 100644 --- a/generator/internal/client_generator.cc +++ b/generator/internal/client_generator.cc @@ -21,6 +21,7 @@ #include "generator/internal/predicate_utils.h" #include "generator/internal/printer.h" #include "absl/strings/str_cat.h" +#include "absl/strings/str_replace.h" #include "google/api/client.pb.h" #include @@ -380,6 +381,12 @@ R"""( std::unique_ptr<::google::cloud::AsyncStreamingReadWriteRpc< __FILE__, __LINE__); } + for (auto const& method : bespoke_methods()) { + HeaderPrint("\n"); + HeaderPrint(absl::StrCat(method.return_type(), " ", method.name(), + method.parameters(), ";")); + } + HeaderPrint( // clang-format off "\n" " private:\n" @@ -716,6 +723,19 @@ std::unique_ptr<::google::cloud::AsyncStreamingReadWriteRpc< __FILE__, __LINE__); } + for (auto const& method : bespoke_methods()) { + CcPrint("\n"); + CcPrint(absl::StrCat( + method.return_type(), R"""( $client_class_name$::)""", method.name(), + absl::StrReplaceAll(method.parameters(), {{" = {}", ""}}), + absl::StrFormat(R"""( { + internal::OptionsSpan span(internal::MergeOptions(std::move(opts), options_)); + return connection_->%s(request); +} +)""", + method.name()))); + } + CcCloseNamespaces(); return {}; } diff --git a/generator/internal/codegen_utils.cc b/generator/internal/codegen_utils.cc index 5be555f1918e2..3e5be23b867d1 100644 --- a/generator/internal/codegen_utils.cc +++ b/generator/internal/codegen_utils.cc @@ -111,6 +111,11 @@ void ProcessArgOmitRpc( ProcessRepeated("omit_rpc", "omitted_rpcs", command_line_args); } +void ProcessArgBespokeMethod( + std::vector>& command_line_args) { + ProcessRepeated("bespoke_method", "bespoke_methods", command_line_args); +} + void ProcessArgServiceEndpointEnvVar( std::vector>& command_line_args) { auto service_endpoint_env_var = @@ -269,6 +274,7 @@ ProcessCommandLineArgs(std::string const& parameters) { ProcessArgCopyrightYear(command_line_args); ProcessArgOmitService(command_line_args); ProcessArgOmitRpc(command_line_args); + ProcessArgBespokeMethod(command_line_args); ProcessArgServiceEndpointEnvVar(command_line_args); ProcessArgEmulatorEndpointEnvVar(command_line_args); ProcessArgEndpointLocationStyle(command_line_args); diff --git a/generator/internal/connection_generator.cc b/generator/internal/connection_generator.cc index 1130dd396a65e..0b093fa339333 100644 --- a/generator/internal/connection_generator.cc +++ b/generator/internal/connection_generator.cc @@ -19,6 +19,7 @@ #include "generator/internal/pagination.h" #include "generator/internal/predicate_utils.h" #include "generator/internal/printer.h" +#include "absl/strings/str_replace.h" #include "absl/strings/str_split.h" #include @@ -57,8 +58,6 @@ Status ConnectionGenerator::GenerateHeader() { {vars("idempotency_policy_header_path"), vars("retry_traits_header_path"), HasLongrunningMethod() ? "google/cloud/no_await_tag.h" : "", IsExperimental() ? "google/cloud/experimental_tag.h" : "", - HasEmitCompletionQueueAccessor() ? "google/cloud/completion_queue.h" - : "", "google/cloud/backoff_policy.h", HasLongrunningMethod() || HasAsyncMethod() ? "google/cloud/future.h" : "", @@ -93,21 +92,7 @@ Status ConnectionGenerator::GenerateHeader() { } } - Status result; - if (HasEmitCompletionQueueAccessor()) { - result = HeaderOpenNamespaces(); - if (!result.ok()) return result; - HeaderPrint(R"""(class $connection_class_name$;)"""); - HeaderCloseNamespaces(); - - result = HeaderOpenNamespaces(NamespaceType::kInternal); - if (!result.ok()) return result; - HeaderPrint( - R"""(StatusOr completion_queue($product_namespace$::$connection_class_name$ const& conn);)"""); - HeaderCloseNamespaces(); - } - - result = HeaderOpenNamespaces(); + auto result = HeaderOpenNamespaces(); if (!result.ok()) return result; HeaderPrint(R"""( @@ -331,13 +316,14 @@ class $connection_class_name$ { __FILE__, __LINE__); } - if (HasEmitCompletionQueueAccessor()) { - HeaderPrint(R"""( protected: - friend StatusOr $product_internal_namespace$::completion_queue( - $connection_class_name$ const& conn); - virtual StatusOr completion_queue() const; -)"""); + for (auto const& method : bespoke_methods()) { + HeaderPrint("\n"); + HeaderPrint(absl::StrCat( + "virtual ", method.return_type(), " ", method.name(), + absl::StrReplaceAll(method.parameters(), {{", Options opts = {}", ""}}), + ";")); } + // close abstract interface Connection base class HeaderPrint("};\n"); @@ -513,13 +499,24 @@ future> __FILE__, __LINE__); } - if (HasEmitCompletionQueueAccessor()) { + for (auto const& method : bespoke_methods()) { + CcPrint("\n"); + std::string make_return = + absl::StrContains(method.return_type(), "future") + ? absl::StrCat("google::cloud::make_ready_", method.return_type()) + : method.return_type(); + CcPrint( - R"""( -StatusOr $connection_class_name$::completion_queue() const { - return Status(StatusCode::kUnimplemented, "not implemented"); + absl::StrCat(method.return_type(), R"""( $connection_class_name$::)""", + method.name(), + absl::StrReplaceAll(method.parameters(), + {{" request, Options opts = {}", ""}}), + " {\n", + absl::StrFormat(R"""( return %s( + Status(StatusCode::kUnimplemented, "not implemented")); } -)"""); +)""", + make_return))); } if (HasGenerateGrpcTransport()) { diff --git a/generator/internal/connection_impl_generator.cc b/generator/internal/connection_impl_generator.cc index dda37fc86532e..cb1ac65aa51a7 100644 --- a/generator/internal/connection_impl_generator.cc +++ b/generator/internal/connection_impl_generator.cc @@ -19,6 +19,7 @@ #include "generator/internal/predicate_utils.h" #include "generator/internal/printer.h" #include "absl/strings/str_cat.h" +#include "absl/strings/str_replace.h" #include namespace google { @@ -120,6 +121,14 @@ class $connection_class_name$Impl HeaderPrintMethod(method, __FILE__, __LINE__, AsyncMethodDeclaration()); } + for (auto const& method : bespoke_methods()) { + HeaderPrint("\n"); + HeaderPrint(absl::StrCat( + method.return_type(), " ", method.name(), + absl::StrReplaceAll(method.parameters(), {{", Options opts = {}", ""}}), + " override;")); + } + HeaderPrint(R"""( private: std::unique_ptr background_; @@ -133,13 +142,6 @@ class $connection_class_name$Impl std::make_shared();)"""); } - if (HasEmitCompletionQueueAccessor()) { - HeaderPrint( - R"""( - StatusOr completion_queue() const override; -)"""); - } - // This closes the *ConnectionImpl class definition. HeaderPrint("\n};\n"); @@ -215,15 +217,6 @@ std::unique_ptr polling_policy(Options const& options) { } // namespace )"""); - if (HasEmitCompletionQueueAccessor()) { - CcPrint(R"""( -StatusOr completion_queue( - $product_namespace$::$connection_class_name$ const& conn) { - return conn.completion_queue(); -} -)"""); - } - // streaming updater functions if (!OmitStreamingUpdater(vars())) { for (auto const& method : methods()) { @@ -258,14 +251,6 @@ void $service_name$$method_name$StreamingUpdater( CcPrintMethod(method, __FILE__, __LINE__, AsyncMethodDefinition(method)); } - if (HasEmitCompletionQueueAccessor()) { - CcPrint(R"""( -StatusOr $connection_class_name$Impl::completion_queue() const { - return background_->cq(); -} -)"""); - } - CcCloseNamespaces(); return {}; } diff --git a/generator/internal/service_code_generator.cc b/generator/internal/service_code_generator.cc index 87138654c0765..02b250cc4056e 100644 --- a/generator/internal/service_code_generator.cc +++ b/generator/internal/service_code_generator.cc @@ -482,6 +482,23 @@ void ServiceCodeGenerator::SetMethods() { for (auto const& mixin_method : mixin_methods_) { methods_.emplace_back(mixin_method.method.get()); } + + auto bespoke_methods_var = service_vars_.find("bespoke_methods"); + if (bespoke_methods_var != service_vars_.end()) { + auto methods = absl::StrSplit(bespoke_methods_var->second, ","); + for (auto const& method : methods) { + std::vector pieces = absl::StrSplit(method, "@@"); + assert(pieces.size() == 4); + cpp::generator::ServiceConfiguration::BespokeMethod bespoke_method; + bespoke_method.set_client_comments(SafeReplaceAll(pieces[0], "@", ",")); + bespoke_method.set_name(SafeReplaceAll(pieces[1], "@", ",")); + bespoke_method.set_return_type(SafeReplaceAll(pieces[2], "@", ",")); + bespoke_method.set_parameters(SafeReplaceAll(pieces[3], "@", ",")); + std::cout << __func__ + << ": bespoke_method=" << bespoke_method.DebugString() << "\n"; + bespoke_methods_.emplace_back(std::move(bespoke_method)); + } + } } std::string ServiceCodeGenerator::GetPbIncludeByTransport() const { @@ -511,11 +528,6 @@ bool ServiceCodeGenerator::IsDeprecated() const { return service_descriptor_->options().deprecated(); } -bool ServiceCodeGenerator::HasEmitCompletionQueueAccessor() const { - return vars().find("emit_completion_queue_accessor") != vars().end() && - vars().at("emit_completion_queue_accessor") == "true"; -} - } // namespace generator_internal } // namespace cloud } // namespace google diff --git a/generator/internal/service_code_generator.h b/generator/internal/service_code_generator.h index e4347db6e0a9e..c267430e08397 100644 --- a/generator/internal/service_code_generator.h +++ b/generator/internal/service_code_generator.h @@ -68,6 +68,10 @@ class ServiceCodeGenerator : public GeneratorInterface { std::string vars(std::string const& key) const; MethodDescriptorList const& methods() const { return methods_; } MethodDescriptorList const& async_methods() const { return async_methods_; } + std::vector const& + bespoke_methods() const { + return bespoke_methods_; + } void SetVars(absl::string_view header_path); VarsDictionary MergeServiceAndMethodVars( google::protobuf::MethodDescriptor const& method) const; @@ -246,8 +250,6 @@ class ServiceCodeGenerator : public GeneratorInterface { */ bool IsDeprecated() const; - bool HasEmitCompletionQueueAccessor() const; - private: void SetMethods(); @@ -270,6 +272,8 @@ class ServiceCodeGenerator : public GeneratorInterface { bool pb_h_system_includes_ = false; MethodDescriptorList methods_; MethodDescriptorList async_methods_; + std::vector + bespoke_methods_; Printer header_; Printer cc_; std::vector mixin_methods_; diff --git a/generator/standalone_main.cc b/generator/standalone_main.cc index 44f626ccd85a5..a5023c2dbf5ca 100644 --- a/generator/standalone_main.cc +++ b/generator/standalone_main.cc @@ -281,6 +281,16 @@ std::vector> GenerateCodeFromProtos( args.emplace_back(absl::StrCat("--cpp_codegen_opt=omit_rpc=", SafeReplaceAll(omit_rpc, ",", "@"))); } + for (auto const& bespoke_method : service.bespoke_methods()) { + args.emplace_back(absl::StrCat( + "--cpp_codegen_opt=bespoke_method=", + absl::StrJoin( + {SafeReplaceAll(bespoke_method.client_comments(), ",", "@"), + SafeReplaceAll(bespoke_method.name(), ",", "@"), + SafeReplaceAll(bespoke_method.return_type(), ",", "@"), + SafeReplaceAll(bespoke_method.parameters(), ",", "@")}, + "@@"))); + } for (auto const& retry_code : service.retryable_status_codes()) { args.emplace_back("--cpp_codegen_opt=retry_status_code=" + retry_code); } @@ -296,11 +306,6 @@ std::vector> GenerateCodeFromProtos( if (service.omit_streaming_updater()) { args.emplace_back("--cpp_codegen_opt=omit_streaming_updater=true"); } - if (service.emit_completion_queue_accessor()) { - args.emplace_back( - "--cpp_codegen_opt=emit_completion_queue_accessor=true"); - } - if (service.generate_round_robin_decorator()) { args.emplace_back( "--cpp_codegen_opt=generate_round_robin_decorator=true"); From 2d6a98e5a95e59131868a3d3b9ec189d2070a70b Mon Sep 17 00:00:00 2001 From: Scott Hart Date: Wed, 28 Jan 2026 19:37:38 -0500 Subject: [PATCH 7/8] regenerated table admin --- .../admin/bigtable_table_admin_connection.cc | 5 ---- .../admin/bigtable_table_admin_connection.h | 27 ------------------- .../bigtable_table_admin_connection_impl.cc | 10 ------- .../bigtable_table_admin_connection_impl.h | 1 - 4 files changed, 43 deletions(-) diff --git a/google/cloud/bigtable/admin/bigtable_table_admin_connection.cc b/google/cloud/bigtable/admin/bigtable_table_admin_connection.cc index cb74e36231ae5..6413380c8ad91 100644 --- a/google/cloud/bigtable/admin/bigtable_table_admin_connection.cc +++ b/google/cloud/bigtable/admin/bigtable_table_admin_connection.cc @@ -390,11 +390,6 @@ BigtableTableAdminConnection::WaitForConsistency( Status(StatusCode::kUnimplemented, "not implemented")); } -StatusOr BigtableTableAdminConnection::completion_queue() - const { - return Status(StatusCode::kUnimplemented, "not implemented"); -} - std::shared_ptr MakeBigtableTableAdminConnection( Options options) { internal::CheckExpectedOptions -namespace google { -namespace cloud { -namespace bigtable_admin { -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN -class BigtableTableAdminConnection; -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END -} // namespace bigtable_admin -} // namespace cloud -} // namespace google - -namespace google { -namespace cloud { -namespace bigtable_admin_internal { -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN -StatusOr completion_queue( - bigtable_admin::BigtableTableAdminConnection const& conn); -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END -} // namespace bigtable_admin_internal -} // namespace cloud -} // namespace google - namespace google { namespace cloud { namespace bigtable_admin { @@ -386,11 +364,6 @@ class BigtableTableAdminConnection { StatusOr> WaitForConsistency( google::bigtable::admin::v2::CheckConsistencyRequest const& request); - - protected: - friend StatusOr bigtable_admin_internal::completion_queue( - BigtableTableAdminConnection const& conn); - virtual StatusOr completion_queue() const; }; /** diff --git a/google/cloud/bigtable/admin/internal/bigtable_table_admin_connection_impl.cc b/google/cloud/bigtable/admin/internal/bigtable_table_admin_connection_impl.cc index c2cc66d3cff53..233be86979261 100644 --- a/google/cloud/bigtable/admin/internal/bigtable_table_admin_connection_impl.cc +++ b/google/cloud/bigtable/admin/internal/bigtable_table_admin_connection_impl.cc @@ -60,11 +60,6 @@ std::unique_ptr polling_policy(Options const& options) { } // namespace -StatusOr completion_queue( - bigtable_admin::BigtableTableAdminConnection const& conn) { - return conn.completion_queue(); -} - BigtableTableAdminConnectionImpl::BigtableTableAdminConnectionImpl( std::unique_ptr background, std::shared_ptr stub, @@ -1298,11 +1293,6 @@ BigtableTableAdminConnectionImpl::AsyncCheckConsistency( std::move(current), std::move(request_copy), __func__); } -StatusOr BigtableTableAdminConnectionImpl::completion_queue() - const { - return background_->cq(); -} - GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END } // namespace bigtable_admin_internal } // namespace cloud diff --git a/google/cloud/bigtable/admin/internal/bigtable_table_admin_connection_impl.h b/google/cloud/bigtable/admin/internal/bigtable_table_admin_connection_impl.h index e9c8a4a80a6f6..ecdddaa38bd66 100644 --- a/google/cloud/bigtable/admin/internal/bigtable_table_admin_connection_impl.h +++ b/google/cloud/bigtable/admin/internal/bigtable_table_admin_connection_impl.h @@ -242,7 +242,6 @@ class BigtableTableAdminConnectionImpl std::unique_ptr background_; std::shared_ptr stub_; Options options_; - StatusOr completion_queue() const override; }; GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END From 0ab1bc676bd99bc7dfe74ac5d5a6e51d55ba2616 Mon Sep 17 00:00:00 2001 From: Scott Hart Date: Wed, 28 Jan 2026 19:37:57 -0500 Subject: [PATCH 8/8] disabling wait consistency free function --- google/cloud/bigtable/wait_for_consistency.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/google/cloud/bigtable/wait_for_consistency.cc b/google/cloud/bigtable/wait_for_consistency.cc index 5cd75ee63b7d2..0828c2992fd81 100644 --- a/google/cloud/bigtable/wait_for_consistency.cc +++ b/google/cloud/bigtable/wait_for_consistency.cc @@ -30,6 +30,7 @@ google::cloud::future> WaitForConsistency( std::shared_ptr const& connection, std::string const& table_id, std::string const& consistency_token, Options options) { +#if 0 auto cq = bigtable_admin_internal::completion_queue(*connection); if (!cq.ok()) return make_ready_future(StatusOr(cq.status())); @@ -48,6 +49,8 @@ google::cloud::future> WaitForConsistency( if (!s.ok()) return s; return Consistency::kConsistent; }); +#endif + return make_ready_future>(internal::UnimplementedError("not implemented")); } namespace {