Google Cloud Bigtable C++ Client  1.33.0
A C++ Client Library for Google Cloud Bigtable
instance_admin.cc
Go to the documentation of this file.
1 // Copyright 2018 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "google/cloud/bigtable/instance_admin.h"
16 #include "google/cloud/bigtable/internal/async_retry_multi_page.h"
17 #include "google/cloud/bigtable/internal/async_retry_op.h"
18 #include "google/cloud/bigtable/internal/async_retry_unary_rpc_and_poll.h"
19 #include "google/cloud/bigtable/internal/unary_client_utils.h"
20 #include "google/cloud/grpc_error_delegate.h"
21 #include "google/cloud/internal/retry_policy.h"
22 #include "google/cloud/internal/throw_delegate.h"
23 #include <google/longrunning/operations.grpc.pb.h>
24 #include <google/protobuf/descriptor.h>
25 #include <google/protobuf/text_format.h>
26 #include <type_traits>
27 #include <unordered_set>
28 // TODO(#5929) - remove after deprecation is completed
29 #include "google/cloud/internal/disable_deprecation_warnings.inc"
30 
31 namespace btadmin = ::google::bigtable::admin::v2;
32 
33 namespace google {
34 namespace cloud {
35 namespace bigtable {
37 static_assert(std::is_copy_assignable<bigtable::InstanceAdmin>::value,
38  "bigtable::InstanceAdmin must be CopyAssignable");
39 
40 using ClientUtils = bigtable::internal::UnaryClientUtils<InstanceAdminClient>;
41 using ::google::cloud::internal::Idempotency;
42 
44  grpc::Status status;
45  InstanceList result;
46  // Copy the policies in effect for the operation.
47  auto rpc_policy = clone_rpc_retry_policy();
48  auto backoff_policy = clone_rpc_backoff_policy();
49 
50  // Build the RPC request, try to minimize copying.
51  std::unordered_set<std::string> unique_failed_locations;
52  std::string page_token;
53  do {
54  btadmin::ListInstancesRequest request;
55  request.set_page_token(std::move(page_token));
56  request.set_parent(project_name());
57 
58  auto response = ClientUtils::MakeCall(
59  *(client_), *rpc_policy, *backoff_policy,
62  "InstanceAdmin::ListInstances", status, Idempotency::kIdempotent);
63  if (!status.ok()) {
64  break;
65  }
66 
67  auto& instances = *response.mutable_instances();
68  std::move(instances.begin(), instances.end(),
69  std::back_inserter(result.instances));
70  auto& failed_locations = *response.mutable_failed_locations();
71  std::move(
72  failed_locations.begin(), failed_locations.end(),
73  std::inserter(unique_failed_locations, unique_failed_locations.end()));
74 
75  page_token = std::move(*response.mutable_next_page_token());
76  } while (!page_token.empty());
77 
78  if (!status.ok()) {
79  return MakeStatusFromRpcError(status);
80  }
81 
82  std::move(unique_failed_locations.begin(), unique_failed_locations.end(),
83  std::back_inserter(result.failed_locations));
84  return result;
85 }
86 
87 future<StatusOr<btadmin::Instance>> InstanceAdmin::CreateInstance(
88  InstanceConfig instance_config) {
89  auto cq = background_threads_->cq();
90  return AsyncCreateInstanceImpl(cq, std::move(instance_config));
91 }
92 
93 future<StatusOr<google::bigtable::admin::v2::Instance>>
94 InstanceAdmin::AsyncCreateInstanceImpl(
95  CompletionQueue& cq, bigtable::InstanceConfig instance_config) {
96  auto request = std::move(instance_config).as_proto();
97  request.set_parent(project_name());
98  for (auto& kv : *request.mutable_clusters()) {
99  kv.second.set_location(project_name() + "/locations/" +
100  kv.second.location());
101  }
102  std::shared_ptr<InstanceAdminClient> client(client_);
103  return internal::AsyncStartPollAfterRetryUnaryRpc<
104  google::bigtable::admin::v2::Instance>(
105  __func__, clone_polling_policy(), clone_rpc_retry_policy(),
106  clone_rpc_backoff_policy(),
107  internal::ConstantIdempotencyPolicy(Idempotency::kNonIdempotent),
108  MetadataUpdatePolicy(project_name(), MetadataParamTypes::PARENT), client,
109  [client](
110  grpc::ClientContext* context,
111  google::bigtable::admin::v2::CreateInstanceRequest const& request,
112  grpc::CompletionQueue* cq) {
113  return client->AsyncCreateInstance(context, request, cq);
114  },
115  std::move(request), cq);
116 }
117 
118 future<StatusOr<btadmin::Cluster>> InstanceAdmin::CreateCluster(
119  ClusterConfig cluster_config, std::string const& instance_id,
120  std::string const& cluster_id) {
121  auto cq = background_threads_->cq();
122  return AsyncCreateClusterImpl(cq, std::move(cluster_config), instance_id,
123  cluster_id);
124 }
125 
126 future<StatusOr<google::bigtable::admin::v2::Cluster>>
127 InstanceAdmin::AsyncCreateClusterImpl(CompletionQueue& cq,
128  ClusterConfig cluster_config,
129  std::string const& instance_id,
130  std::string const& cluster_id) {
131  auto cluster = std::move(cluster_config).as_proto();
132  cluster.set_location(project_name() + "/locations/" + cluster.location());
133  btadmin::CreateClusterRequest request;
134  request.mutable_cluster()->Swap(&cluster);
135  auto parent = InstanceName(instance_id);
136  request.set_parent(parent);
137  request.set_cluster_id(cluster_id);
138 
139  std::shared_ptr<InstanceAdminClient> client(client_);
140  return internal::AsyncStartPollAfterRetryUnaryRpc<
141  google::bigtable::admin::v2::Cluster>(
142  __func__, clone_polling_policy(), clone_rpc_retry_policy(),
143  clone_rpc_backoff_policy(),
144  internal::ConstantIdempotencyPolicy(Idempotency::kNonIdempotent),
145  MetadataUpdatePolicy(parent, MetadataParamTypes::PARENT), client,
146  [client](grpc::ClientContext* context,
147  google::bigtable::admin::v2::CreateClusterRequest const& request,
148  grpc::CompletionQueue* cq) {
149  return client->AsyncCreateCluster(context, request, cq);
150  },
151  std::move(request), cq);
152 }
153 
154 future<StatusOr<google::bigtable::admin::v2::Instance>>
156  auto cq = background_threads_->cq();
157  return AsyncUpdateInstanceImpl(cq, std::move(instance_update_config));
158 }
159 
160 future<StatusOr<google::bigtable::admin::v2::Instance>>
161 InstanceAdmin::AsyncUpdateInstanceImpl(
162  CompletionQueue& cq, InstanceUpdateConfig instance_update_config) {
163  auto name = instance_update_config.GetName();
164  auto request = std::move(instance_update_config).as_proto();
165 
166  std::shared_ptr<InstanceAdminClient> client(client_);
167  return internal::AsyncStartPollAfterRetryUnaryRpc<
168  google::bigtable::admin::v2::Instance>(
169  __func__, clone_polling_policy(), clone_rpc_retry_policy(),
170  clone_rpc_backoff_policy(),
171  internal::ConstantIdempotencyPolicy(Idempotency::kNonIdempotent),
172  MetadataUpdatePolicy(name, MetadataParamTypes::INSTANCE_NAME), client,
173  [client](grpc::ClientContext* context,
174  google::bigtable::admin::v2::PartialUpdateInstanceRequest const&
175  request,
176  grpc::CompletionQueue* cq) {
177  return client->AsyncUpdateInstance(context, request, cq);
178  },
179  std::move(request), cq);
180 }
181 
182 StatusOr<btadmin::Instance> InstanceAdmin::GetInstance(
183  std::string const& instance_id) {
184  grpc::Status status;
185  // Copy the policies in effect for the operation.
186  auto rpc_policy = clone_rpc_retry_policy();
187  auto backoff_policy = clone_rpc_backoff_policy();
188 
189  btadmin::GetInstanceRequest request;
190  // Setting instance name.
191  auto name = InstanceName(instance_id);
192  request.set_name(name);
193 
194  // Call RPC call to get response
195  auto result = ClientUtils::MakeCall(
196  *(client_), *rpc_policy, *backoff_policy,
197  MetadataUpdatePolicy(name, MetadataParamTypes::NAME),
198  &InstanceAdminClient::GetInstance, request, "InstanceAdmin::GetInstance",
199  status, Idempotency::kIdempotent);
200  if (!status.ok()) {
201  return MakeStatusFromRpcError(status);
202  }
203  return result;
204 }
205 
206 Status InstanceAdmin::DeleteInstance(std::string const& instance_id) {
207  grpc::Status status;
208  btadmin::DeleteInstanceRequest request;
209  auto name = InstanceName(instance_id);
210  request.set_name(name);
211 
212  // This API is not idempotent, lets call it without retry
213  ClientUtils::MakeNonIdempotentCall(
214  *(client_), clone_rpc_retry_policy(),
215  MetadataUpdatePolicy(name, MetadataParamTypes::NAME),
217  "InstanceAdmin::DeleteInstance", status);
218  return MakeStatusFromRpcError(status);
219 }
220 
221 StatusOr<btadmin::Cluster> InstanceAdmin::GetCluster(
222  std::string const& instance_id, std::string const& cluster_id) {
223  grpc::Status status;
224  auto rpc_policy = clone_rpc_retry_policy();
225  auto backoff_policy = clone_rpc_backoff_policy();
226 
227  btadmin::GetClusterRequest request;
228  auto name = ClusterName(instance_id, cluster_id);
229  request.set_name(name);
230 
231  auto result = ClientUtils::MakeCall(
232  *(client_), *rpc_policy, *backoff_policy,
233  MetadataUpdatePolicy(name, MetadataParamTypes::NAME),
234  &InstanceAdminClient::GetCluster, request, "InstanceAdmin::GetCluster",
235  status, Idempotency::kIdempotent);
236  if (!status.ok()) {
237  return MakeStatusFromRpcError(status);
238  }
239  return result;
240 }
241 
243  return ListClusters("-");
244 }
245 
247  std::string const& instance_id) {
248  grpc::Status status;
249  ClusterList result;
250  std::unordered_set<std::string> unique_failed_locations;
251  std::string page_token;
252 
253  // Copy the policies in effect for the operation.
254  auto rpc_policy = clone_rpc_retry_policy();
255  auto backoff_policy = clone_rpc_backoff_policy();
256 
257  do {
258  // Build the RPC request, try to minimize copying.
259  btadmin::ListClustersRequest request;
260  request.set_page_token(std::move(page_token));
261  auto parent = InstanceName(instance_id);
262  request.set_parent(parent);
263 
264  auto response = ClientUtils::MakeCall(
265  *(client_), *rpc_policy, *backoff_policy,
266  MetadataUpdatePolicy(parent, MetadataParamTypes::PARENT),
268  "InstanceAdmin::ListClusters", status, Idempotency::kIdempotent);
269  if (!status.ok()) {
270  break;
271  }
272 
273  auto& clusters = *response.mutable_clusters();
274  std::move(clusters.begin(), clusters.end(),
275  std::back_inserter(result.clusters));
276  auto& failed_locations = *response.mutable_failed_locations();
277  std::move(
278  failed_locations.begin(), failed_locations.end(),
279  std::inserter(unique_failed_locations, unique_failed_locations.end()));
280  page_token = std::move(*response.mutable_next_page_token());
281  } while (!page_token.empty());
282 
283  if (!status.ok()) {
284  return MakeStatusFromRpcError(status);
285  }
286 
287  std::move(unique_failed_locations.begin(), unique_failed_locations.end(),
288  std::back_inserter(result.failed_locations));
289  return result;
290 }
291 
292 future<StatusOr<google::bigtable::admin::v2::Cluster>>
294  auto cq = background_threads_->cq();
295  return AsyncUpdateClusterImpl(cq, std::move(cluster_config));
296 }
297 
298 future<StatusOr<google::bigtable::admin::v2::Cluster>>
299 InstanceAdmin::AsyncUpdateClusterImpl(CompletionQueue& cq,
300  ClusterConfig cluster_config) {
301  auto request = std::move(cluster_config).as_proto();
302  auto name = request.name();
303 
304  std::shared_ptr<InstanceAdminClient> client(client_);
305  return internal::AsyncStartPollAfterRetryUnaryRpc<
306  google::bigtable::admin::v2::Cluster>(
307  __func__, clone_polling_policy(), clone_rpc_retry_policy(),
308  clone_rpc_backoff_policy(),
309  internal::ConstantIdempotencyPolicy(Idempotency::kNonIdempotent),
310  MetadataUpdatePolicy(name, MetadataParamTypes::NAME), client,
311  [client](grpc::ClientContext* context,
312  google::bigtable::admin::v2::Cluster const& request,
313  grpc::CompletionQueue* cq) {
314  return client->AsyncUpdateCluster(context, request, cq);
315  },
316  std::move(request), cq);
317 }
318 
319 Status InstanceAdmin::DeleteCluster(std::string const& instance_id,
320  std::string const& cluster_id) {
321  grpc::Status status;
322  btadmin::DeleteClusterRequest request;
323  auto name = ClusterName(instance_id, cluster_id);
324  request.set_name(name);
325 
326  auto metadata_update_policy =
327  MetadataUpdatePolicy(name, MetadataParamTypes::NAME);
328 
329  // This API is not idempotent, lets call it without retry
330  ClientUtils::MakeNonIdempotentCall(
331  *(client_), clone_rpc_retry_policy(), metadata_update_policy,
333  "InstanceAdmin::DeleteCluster", status);
334  return MakeStatusFromRpcError(status);
335 }
336 
337 StatusOr<btadmin::AppProfile> InstanceAdmin::CreateAppProfile(
338  std::string const& instance_id, AppProfileConfig config) {
339  grpc::Status status;
340  auto request = std::move(config).as_proto();
341  auto parent = InstanceName(instance_id);
342  request.set_parent(parent);
343 
344  // This is a non-idempotent API, use the correct retry loop for this type of
345  // operation.
346  auto result = ClientUtils::MakeNonIdempotentCall(
347  *(client_), clone_rpc_retry_policy(),
348  MetadataUpdatePolicy(parent, MetadataParamTypes::PARENT),
350  "InstanceAdmin::CreateAppProfile", status);
351 
352  if (!status.ok()) {
353  return MakeStatusFromRpcError(status);
354  }
355  return result;
356 }
357 
358 StatusOr<btadmin::AppProfile> InstanceAdmin::GetAppProfile(
359  std::string const& instance_id, std::string const& profile_id) {
360  grpc::Status status;
361  btadmin::GetAppProfileRequest request;
362  auto name = AppProfileName(instance_id, profile_id);
363  request.set_name(name);
364 
365  auto result = ClientUtils::MakeCall(
366  *(client_), clone_rpc_retry_policy(), clone_rpc_backoff_policy(),
367  MetadataUpdatePolicy(name, MetadataParamTypes::NAME),
369  "InstanceAdmin::GetAppProfile", status, Idempotency::kIdempotent);
370 
371  if (!status.ok()) {
372  return MakeStatusFromRpcError(status);
373  }
374  return result;
375 }
376 
377 future<StatusOr<btadmin::AppProfile>> InstanceAdmin::UpdateAppProfile(
378  std::string const& instance_id, std::string const& profile_id,
379  AppProfileUpdateConfig config) {
380  auto cq = background_threads_->cq();
381  return AsyncUpdateAppProfileImpl(cq, instance_id, profile_id,
382  std::move(config));
383 }
384 
385 future<StatusOr<google::bigtable::admin::v2::AppProfile>>
386 InstanceAdmin::AsyncUpdateAppProfileImpl(CompletionQueue& cq,
387  std::string const& instance_id,
388  std::string const& profile_id,
389  AppProfileUpdateConfig config) {
390  auto request = std::move(config).as_proto();
391  auto name = AppProfileName(instance_id, profile_id);
392  request.mutable_app_profile()->set_name(name);
393 
394  std::shared_ptr<InstanceAdminClient> client(client_);
395  return internal::AsyncStartPollAfterRetryUnaryRpc<
396  google::bigtable::admin::v2::AppProfile>(
397  __func__, clone_polling_policy(), clone_rpc_retry_policy(),
398  clone_rpc_backoff_policy(),
399  internal::ConstantIdempotencyPolicy(Idempotency::kNonIdempotent),
400  MetadataUpdatePolicy(name, MetadataParamTypes::APP_PROFILE_NAME), client,
401  [client](
402  grpc::ClientContext* context,
403  google::bigtable::admin::v2::UpdateAppProfileRequest const& request,
404  grpc::CompletionQueue* cq) {
405  return client->AsyncUpdateAppProfile(context, request, cq);
406  },
407  std::move(request), cq);
408 }
409 
410 StatusOr<std::vector<btadmin::AppProfile>> InstanceAdmin::ListAppProfiles(
411  std::string const& instance_id) {
412  grpc::Status status;
413  std::vector<btadmin::AppProfile> result;
414  std::string page_token;
415  // Copy the policies in effect for the operation.
416  auto rpc_policy = clone_rpc_retry_policy();
417  auto backoff_policy = clone_rpc_backoff_policy();
418  auto parent = InstanceName(instance_id);
419 
420  do {
421  // Build the RPC request, try to minimize copying.
422  btadmin::ListAppProfilesRequest request;
423  request.set_page_token(std::move(page_token));
424  request.set_parent(parent);
425 
426  auto response = ClientUtils::MakeCall(
427  *(client_), *rpc_policy, *backoff_policy,
428  MetadataUpdatePolicy(parent, MetadataParamTypes::PARENT),
430  "InstanceAdmin::ListAppProfiles", status, Idempotency::kIdempotent);
431  if (!status.ok()) {
432  break;
433  }
434 
435  for (auto& x : *response.mutable_app_profiles()) {
436  result.emplace_back(std::move(x));
437  }
438  page_token = std::move(*response.mutable_next_page_token());
439  } while (!page_token.empty());
440 
441  if (!status.ok()) {
442  return MakeStatusFromRpcError(status);
443  }
444  return result;
445 }
446 
447 Status InstanceAdmin::DeleteAppProfile(std::string const& instance_id,
448  std::string const& profile_id,
449  bool ignore_warnings) {
450  grpc::Status status;
451  btadmin::DeleteAppProfileRequest request;
452  auto name = AppProfileName(instance_id, profile_id);
453  request.set_name(name);
454  request.set_ignore_warnings(ignore_warnings);
455 
456  ClientUtils::MakeNonIdempotentCall(
457  *(client_), clone_rpc_retry_policy(),
458  MetadataUpdatePolicy(name, MetadataParamTypes::NAME),
460  "InstanceAdmin::DeleteAppProfile", status);
461 
462  return MakeStatusFromRpcError(status);
463 }
464 
466  std::string const& instance_id) {
467  grpc::Status status;
468  auto rpc_policy = clone_rpc_retry_policy();
469  auto backoff_policy = clone_rpc_backoff_policy();
470 
471  ::google::iam::v1::GetIamPolicyRequest request;
472  auto resource = InstanceName(instance_id);
473  request.set_resource(resource);
474 
475  MetadataUpdatePolicy metadata_update_policy(resource,
476  MetadataParamTypes::RESOURCE);
477 
478  auto proto = ClientUtils::MakeCall(
479  *(client_), *rpc_policy, *backoff_policy, metadata_update_policy,
481  "InstanceAdmin::GetIamPolicy", status, Idempotency::kIdempotent);
482 
483  if (!status.ok()) {
484  return MakeStatusFromRpcError(status);
485  }
486 
487  return ProtoToWrapper(std::move(proto));
488 }
489 
490 StatusOr<google::iam::v1::Policy> InstanceAdmin::GetNativeIamPolicy(
491  std::string const& instance_id) {
492  grpc::Status status;
493  auto rpc_policy = clone_rpc_retry_policy();
494  auto backoff_policy = clone_rpc_backoff_policy();
495 
496  ::google::iam::v1::GetIamPolicyRequest request;
497  auto resource = InstanceName(instance_id);
498  request.set_resource(resource);
499 
500  MetadataUpdatePolicy metadata_update_policy(resource,
501  MetadataParamTypes::RESOURCE);
502 
503  auto proto = ClientUtils::MakeCall(
504  *(client_), *rpc_policy, *backoff_policy, metadata_update_policy,
506  "InstanceAdmin::GetIamPolicy", status, Idempotency::kIdempotent);
507 
508  if (!status.ok()) {
509  return MakeStatusFromRpcError(status);
510  }
511 
512  return proto;
513 }
514 
516  std::string const& instance_id,
517  google::cloud::IamBindings const& iam_bindings, std::string const& etag) {
518  grpc::Status status;
519  auto rpc_policy = clone_rpc_retry_policy();
520  auto backoff_policy = clone_rpc_backoff_policy();
521 
522  ::google::iam::v1::Policy policy;
523  policy.set_etag(etag);
524  auto role_bindings = iam_bindings.bindings();
525  for (auto& binding : role_bindings) {
526  auto& new_binding = *policy.add_bindings();
527  new_binding.set_role(binding.first);
528  for (auto const& member : binding.second) {
529  new_binding.add_members(member);
530  }
531  }
532 
533  ::google::iam::v1::SetIamPolicyRequest request;
534  auto resource = InstanceName(instance_id);
535  request.set_resource(resource);
536  *request.mutable_policy() = std::move(policy);
537 
538  MetadataUpdatePolicy metadata_update_policy(resource,
539  MetadataParamTypes::RESOURCE);
540 
541  auto proto = ClientUtils::MakeCall(
542  *(client_), *rpc_policy, *backoff_policy, metadata_update_policy,
544  "InstanceAdmin::SetIamPolicy", status, Idempotency::kIdempotent);
545 
546  if (!status.ok()) {
547  return MakeStatusFromRpcError(status);
548  }
549 
550  return ProtoToWrapper(std::move(proto));
551 }
552 
553 StatusOr<google::iam::v1::Policy> InstanceAdmin::SetIamPolicy(
554  std::string const& instance_id, google::iam::v1::Policy const& iam_policy) {
555  grpc::Status status;
556  auto rpc_policy = clone_rpc_retry_policy();
557  auto backoff_policy = clone_rpc_backoff_policy();
558 
559  ::google::iam::v1::SetIamPolicyRequest request;
560  auto resource = InstanceName(instance_id);
561  request.set_resource(resource);
562  *request.mutable_policy() = iam_policy;
563 
564  MetadataUpdatePolicy metadata_update_policy(resource,
565  MetadataParamTypes::RESOURCE);
566 
567  auto proto = ClientUtils::MakeCall(
568  *(client_), *rpc_policy, *backoff_policy, metadata_update_policy,
570  "InstanceAdmin::SetIamPolicy", status, Idempotency::kIdempotent);
571 
572  if (!status.ok()) {
573  return MakeStatusFromRpcError(status);
574  }
575 
576  return proto;
577 }
578 
579 StatusOr<std::vector<std::string>> InstanceAdmin::TestIamPermissions(
580  std::string const& instance_id,
581  std::vector<std::string> const& permissions) {
582  grpc::Status status;
583  ::google::iam::v1::TestIamPermissionsRequest request;
584  auto resource = InstanceName(instance_id);
585  request.set_resource(resource);
586 
587  // Copy the policies in effect for the operation.
588  auto rpc_policy = clone_rpc_retry_policy();
589  auto backoff_policy = clone_rpc_backoff_policy();
590 
591  for (auto const& permission : permissions) {
592  request.add_permissions(permission);
593  }
594 
595  MetadataUpdatePolicy metadata_update_policy(resource,
596  MetadataParamTypes::RESOURCE);
597 
598  auto response = ClientUtils::MakeCall(
599  *(client_), *rpc_policy, *backoff_policy, metadata_update_policy,
601  "InstanceAdmin::TestIamPermissions", status, Idempotency::kIdempotent);
602 
603  std::vector<std::string> resource_permissions;
604 
605  for (auto& permission : *response.mutable_permissions()) {
606  resource_permissions.push_back(permission);
607  }
608 
609  if (!status.ok()) {
610  return MakeStatusFromRpcError(status);
611  }
612 
613  return resource_permissions;
614 }
615 
616 StatusOr<google::cloud::IamPolicy> InstanceAdmin::ProtoToWrapper(
617  google::iam::v1::Policy proto) {
618  google::cloud::IamPolicy result;
619  result.version = proto.version();
620  result.etag = std::move(*proto.mutable_etag());
621  for (auto& binding : *proto.mutable_bindings()) {
622  std::vector<google::protobuf::FieldDescriptor const*> field_descs;
623  // On newer versions of Protobuf (circa 3.9.1) `GetReflection()` changed
624  // from a virtual member function to a static member function. clang-tidy
625  // warns (and we turn all warnings to errors) about using the static
626  // version via the object, as we do below. Disable the warning because that
627  // seems like the only portable solution.
628  // NOLINTNEXTLINE(readability-static-accessed-through-instance)
629  binding.GetReflection()->ListFields(binding, &field_descs);
630  for (auto const* field_desc : field_descs) {
631  if (field_desc->name() != "members" && field_desc->name() != "role") {
632  std::stringstream os;
633  os << "IamBinding field \"" << field_desc->name()
634  << "\" is unknown to Bigtable C++ client. Please use "
635  "GetNativeIamPolicy() and its"
636  "SetIamPolicy() overload.";
637  return Status(StatusCode::kUnimplemented, os.str());
638  }
639  }
640  for (auto& member : *binding.mutable_members()) {
641  result.bindings.AddMember(binding.role(), std::move(member));
642  }
643  }
644  return result;
645 }
646 
648 } // namespace bigtable
649 } // namespace cloud
650 } // namespace google