Getting Started with Bigtable Instance Administrative Operations

This example is a very simple "Instance Admin" application, which illustrates how to:

  • Create a production instance.
  • List the existing instances.
  • Get the metadata for an instance.
  • List all the clusters in an instance.
  • Delete an instance.

Run the example

This example uses the Cloud Bigtable C++ Client Library to communicate with Cloud Bigtable.

To run the example program, follow the instructions for the example on GitHub.

Include the Necessary Headers

The example uses the following headers:

#include "google/cloud/bigtable/admin/bigtable_instance_admin_client.h"

Define aliases

To make the example less verbose we define some aliases:

  namespace cbt = ::google::cloud::bigtable;
  namespace cbta = ::google::cloud::bigtable_admin;
  using ::google::cloud::future;
  using ::google::cloud::Location;
  using ::google::cloud::Project;
  using ::google::cloud::Status;
  using ::google::cloud::StatusOr;

Connect to the Cloud Bigtable Instance Admin Endpoint.

Create an object of type bigtable_admin::BigtableInstanceAdminClient to obtain information about Instances, Clusters, Application Profiles, and to change the IAM permissions in a Cloud Bigtable instance:

  auto instance_admin = cbta::BigtableInstanceAdminClient(
      cbta::MakeBigtableInstanceAdminConnection());
See Also

https://cloud.google.com/bigtable/docs/instances-clusters-nodes for more information about Cloud Bigtable instances, clusters, and nodes.

See Also

https://cloud.google.com/bigtable/docs/app-profiles for more information about Cloud Bigtable application profiles.

See Also

https://cloud.google.com/bigtable/docs/access-control for more information about access controls via IAM permissions on Cloud Bigtable.

Check if an Instance already exists

  std::cout << "\nCheck Instance exists:\n";
  auto const project = Project(project_id);
  std::string const project_name = project.FullName();
  StatusOr<google::bigtable::admin::v2::ListInstancesResponse> instances =
      instance_admin.ListInstances(project_name);
  if (!instances) throw std::move(instances).status();
  if (!instances->failed_locations().empty()) {
    std::cerr
        << "The service tells us it has no information about these locations:";
    for (auto const& failed_location : instances->failed_locations()) {
      std::cerr << " " << failed_location;
    }
    std::cerr << ". Continuing anyway\n";
  }
  std::string const instance_name = cbt::InstanceName(project_id, instance_id);
  auto is_instance =
      [&instance_name](google::bigtable::admin::v2::Instance const& i) {
        return i.name() == instance_name;
      };
  auto const& ins = instances->instances();
  auto instance_exists =
      std::find_if(ins.begin(), ins.end(), is_instance) != ins.end();
  std::cout << "The instance " << instance_id
            << (instance_exists ? " already exists" : " does not exist")
            << "\n";
See Also

BigtableInstanceAdminClient::GetInstance() for another operation to query if an instance exists.

Create a Production Instance

Use BigtableInstanceAdminClient::CreateInstance() to create a new instance:

    std::cout << "\nCreating a PRODUCTION Instance: ";

    // production instance needs at least 3 nodes
    google::bigtable::admin::v2::Cluster c;
    c.set_location(Location(project, zone).FullName());
    c.set_serve_nodes(3);
    c.set_default_storage_type(google::bigtable::admin::v2::HDD);

    google::bigtable::admin::v2::Instance in;
    in.set_display_name("Sample Instance");
    in.set_type(google::bigtable::admin::v2::Instance::PRODUCTION);

    future<void> creation_done =
        instance_admin
            .CreateInstance(project_name, instance_id, std::move(in),
                            {{cluster_id, std::move(c)}})
            .then(
                [instance_id](
                    future<StatusOr<google::bigtable::admin::v2::Instance>> f) {
                  auto instance = f.get();
                  if (!instance) {
                    std::cerr << "Could not create instance " << instance_id
                              << "\n";
                    throw std::move(instance).status();
                  }
                  std::cout << "Successfully created instance: "
                            << instance->DebugString() << "\n";
                });
    // Note how this blocks until the instance is created. In production code
    // you may want to perform this task asynchronously.
    creation_done.get();
    std::cout << "DONE\n";

List Instances in a Project

Use BigtableInstanceAdminClient::ListInstances() to list all the instances in the project:

  std::cout << "\nListing Instances:\n";
  instances = instance_admin.ListInstances(project_name);
  if (!instances) throw std::move(instances).status();
  if (!instances->failed_locations().empty()) {
    std::cerr
        << "The service tells us it has no information about these locations:";
    for (auto const& failed_location : instances->failed_locations()) {
      std::cerr << " " << failed_location;
    }
    std::cerr << ". Continuing anyway\n";
  }
  for (auto const& instance : instances->instances()) {
    std::cout << "  " << instance.name() << "\n";
  }
  std::cout << "DONE\n";
See Also

The gRPC API documentation for ListInstances has more details on when failed_locations might be populated.

Get an Instance Metadata

Use BigtableInstanceAdminClient::GetInstance() to retrieve the metadata of an instance:

  std::cout << "\nGet Instance:\n";
  auto instance = instance_admin.GetInstance(instance_name);
  if (!instance) throw std::move(instance).status();
  std::cout << "Instance details :\n" << instance->DebugString() << "\n";

List clusters in an Instance

Use BigtableInstanceAdminClient::ListClusters() to list all the clusters in an instance (or all the clusters in a project):

  std::cout << "\nListing Clusters:\n";
  StatusOr<google::bigtable::admin::v2::ListClustersResponse> cluster_list =
      instance_admin.ListClusters(instance_name);
  if (!cluster_list) throw std::move(cluster_list).status();
  if (!cluster_list->failed_locations().empty()) {
    std::cout << "The Cloud Bigtable service reports that the following "
                 "locations are temporarily unavailable and no information "
                 "about clusters in these locations can be obtained:\n";
    for (auto const& failed_location : cluster_list->failed_locations()) {
      std::cout << failed_location << "\n";
    }
  }
  std::cout << "Cluster Name List:\n";
  for (auto const& cluster : cluster_list->clusters()) {
    std::cout << "Cluster Name: " << cluster.name() << "\n";
  }
  std::cout << "DONE\n";
See Also

The bigtable_admin::BigtableInstanceAdminClient class also has functions to create, update, delete, and retrieve the metadata of a Cluster.

See Also

The gRPC API documentation for ListClusters has more details on when failed_locations might be populated.

Delete an instance

Finally, use BigtableInstanceAdminClient::DeleteInstance() to delete an instance:

  std::cout << "Deleting instance " << instance_id << "\n";
  Status delete_status = instance_admin.DeleteInstance(instance_name);
  if (!delete_status.ok()) throw std::runtime_error(delete_status.message());
  std::cout << "DONE\n";

Put it all together

Here is the full example


#include "google/cloud/bigtable/admin/bigtable_instance_admin_client.h"
#include "google/cloud/bigtable/examples/bigtable_examples_common.h"
#include "google/cloud/bigtable/resource_names.h"
#include "google/cloud/bigtable/testing/cleanup_stale_resources.h"
#include "google/cloud/bigtable/testing/random_names.h"
#include "google/cloud/internal/getenv.h"
#include "google/cloud/internal/random.h"
#include "google/cloud/location.h"
#include "google/cloud/log.h"
#include "google/cloud/project.h"
#include <algorithm>
#include <iostream>

namespace {

using ::google::cloud::bigtable::examples::Usage;

void BigtableHelloInstance(std::vector<std::string> const& argv) {
  if (argv.size() != 4) {
    throw Usage{
        "hello-instance <project-id> <instance-id> <cluster-id> <zone>"};
  }

  std::string const& project_id = argv[0];
  std::string const& instance_id = argv[1];
  std::string const& cluster_id = argv[2];
  std::string const& zone = argv[3];

  namespace cbt = ::google::cloud::bigtable;
  namespace cbta = ::google::cloud::bigtable_admin;
  using ::google::cloud::future;
  using ::google::cloud::Location;
  using ::google::cloud::Project;
  using ::google::cloud::Status;
  using ::google::cloud::StatusOr;

  // Connect to the Cloud Bigtable admin endpoint.
  auto instance_admin = cbta::BigtableInstanceAdminClient(
      cbta::MakeBigtableInstanceAdminConnection());

  std::cout << "\nCheck Instance exists:\n";
  auto const project = Project(project_id);
  std::string const project_name = project.FullName();
  StatusOr<google::bigtable::admin::v2::ListInstancesResponse> instances =
      instance_admin.ListInstances(project_name);
  if (!instances) throw std::move(instances).status();
  if (!instances->failed_locations().empty()) {
    std::cerr
        << "The service tells us it has no information about these locations:";
    for (auto const& failed_location : instances->failed_locations()) {
      std::cerr << " " << failed_location;
    }
    std::cerr << ". Continuing anyway\n";
  }
  std::string const instance_name = cbt::InstanceName(project_id, instance_id);
  auto is_instance =
      [&instance_name](google::bigtable::admin::v2::Instance const& i) {
        return i.name() == instance_name;
      };
  auto const& ins = instances->instances();
  auto instance_exists =
      std::find_if(ins.begin(), ins.end(), is_instance) != ins.end();
  std::cout << "The instance " << instance_id
            << (instance_exists ? " already exists" : " does not exist")
            << "\n";

  // Create instance if it does not exist
  if (!instance_exists) {
    std::cout << "\nCreating a PRODUCTION Instance: ";

    // production instance needs at least 3 nodes
    google::bigtable::admin::v2::Cluster c;
    c.set_location(Location(project, zone).FullName());
    c.set_serve_nodes(3);
    c.set_default_storage_type(google::bigtable::admin::v2::HDD);

    google::bigtable::admin::v2::Instance in;
    in.set_display_name("Sample Instance");
    in.set_type(google::bigtable::admin::v2::Instance::PRODUCTION);

    future<void> creation_done =
        instance_admin
            .CreateInstance(project_name, instance_id, std::move(in),
                            {{cluster_id, std::move(c)}})
            .then(
                [instance_id](
                    future<StatusOr<google::bigtable::admin::v2::Instance>> f) {
                  auto instance = f.get();
                  if (!instance) {
                    std::cerr << "Could not create instance " << instance_id
                              << "\n";
                    throw std::move(instance).status();
                  }
                  std::cout << "Successfully created instance: "
                            << instance->DebugString() << "\n";
                });
    // Note how this blocks until the instance is created. In production code
    // you may want to perform this task asynchronously.
    creation_done.get();
    std::cout << "DONE\n";
  }

  std::cout << "\nListing Instances:\n";
  instances = instance_admin.ListInstances(project_name);
  if (!instances) throw std::move(instances).status();
  if (!instances->failed_locations().empty()) {
    std::cerr
        << "The service tells us it has no information about these locations:";
    for (auto const& failed_location : instances->failed_locations()) {
      std::cerr << " " << failed_location;
    }
    std::cerr << ". Continuing anyway\n";
  }
  for (auto const& instance : instances->instances()) {
    std::cout << "  " << instance.name() << "\n";
  }
  std::cout << "DONE\n";

  std::cout << "\nGet Instance:\n";
  auto instance = instance_admin.GetInstance(instance_name);
  if (!instance) throw std::move(instance).status();
  std::cout << "Instance details :\n" << instance->DebugString() << "\n";

  std::cout << "\nListing Clusters:\n";
  StatusOr<google::bigtable::admin::v2::ListClustersResponse> cluster_list =
      instance_admin.ListClusters(instance_name);
  if (!cluster_list) throw std::move(cluster_list).status();
  if (!cluster_list->failed_locations().empty()) {
    std::cout << "The Cloud Bigtable service reports that the following "
                 "locations are temporarily unavailable and no information "
                 "about clusters in these locations can be obtained:\n";
    for (auto const& failed_location : cluster_list->failed_locations()) {
      std::cout << failed_location << "\n";
    }
  }
  std::cout << "Cluster Name List:\n";
  for (auto const& cluster : cluster_list->clusters()) {
    std::cout << "Cluster Name: " << cluster.name() << "\n";
  }
  std::cout << "DONE\n";

  std::cout << "Deleting instance " << instance_id << "\n";
  Status delete_status = instance_admin.DeleteInstance(instance_name);
  if (!delete_status.ok()) throw std::runtime_error(delete_status.message());
  std::cout << "DONE\n";
}

void RunAll(std::vector<std::string> const& argv) {
  namespace examples = ::google::cloud::bigtable::examples;
  namespace cbta = ::google::cloud::bigtable_admin;

  if (!argv.empty()) throw Usage{"auto"};
  if (!examples::RunAdminIntegrationTests()) return;
  examples::CheckEnvironmentVariablesAreSet({
      "GOOGLE_CLOUD_PROJECT",
      "GOOGLE_CLOUD_CPP_BIGTABLE_TEST_ZONE_A",
  });
  auto const project_id =
      google::cloud::internal::GetEnv("GOOGLE_CLOUD_PROJECT").value();
  auto const zone_a =
      google::cloud::internal::GetEnv("GOOGLE_CLOUD_CPP_BIGTABLE_TEST_ZONE_A")
          .value();

  auto generator = google::cloud::internal::DefaultPRNG(std::random_device{}());
  google::cloud::bigtable::testing::CleanupStaleInstances(
      cbta::MakeBigtableInstanceAdminConnection(), project_id);
  auto const instance_id =
      google::cloud::bigtable::testing::RandomInstanceId(generator);
  auto const cluster_id = instance_id + "-c1";

  std::cout << "\nRunning the BigtableHelloInstance() example" << std::endl;
  BigtableHelloInstance({project_id, instance_id, cluster_id, zone_a});
}

}  // namespace

int main(int argc, char* argv[]) try {
  google::cloud::bigtable::examples::Example example({
      {"auto", RunAll},
      {"hello-instance", BigtableHelloInstance},
  });
  return example.Run(argc, argv);
} catch (std::exception const& ex) {
  std::cerr << ex.what() << "\n";
  ::google::cloud::LogSink::Instance().Flush();
  return 1;
}