diff --git a/google-cloud-clients/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/InstanceAdminClient.java b/google-cloud-clients/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/InstanceAdminClient.java
new file mode 100644
index 000000000000..72ed4aaba45d
--- /dev/null
+++ b/google-cloud-clients/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/InstanceAdminClient.java
@@ -0,0 +1,454 @@
+package com.google.cloud.bigtable.admin.v2;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import com.google.api.core.ApiFunction;
+import com.google.api.core.ApiFuture;
+import com.google.api.core.BetaApi;
+import com.google.api.core.SettableApiFuture;
+import com.google.api.gax.longrunning.OperationFuture;
+import com.google.bigtable.admin.v2.AppProfileName;
+import com.google.bigtable.admin.v2.ClusterName;
+import com.google.bigtable.admin.v2.CreateAppProfileRequest;
+import com.google.bigtable.admin.v2.CreateClusterMetadata;
+import com.google.bigtable.admin.v2.CreateClusterRequest;
+import com.google.bigtable.admin.v2.CreateInstanceMetadata;
+import com.google.bigtable.admin.v2.DeleteAppProfileRequest;
+import com.google.bigtable.admin.v2.DeleteClusterRequest;
+import com.google.bigtable.admin.v2.DeleteInstanceRequest;
+import com.google.bigtable.admin.v2.GetAppProfileRequest;
+import com.google.bigtable.admin.v2.GetClusterRequest;
+import com.google.bigtable.admin.v2.GetInstanceRequest;
+import com.google.bigtable.admin.v2.InstanceName;
+import com.google.bigtable.admin.v2.ListAppProfilesRequest;
+import com.google.bigtable.admin.v2.ListAppProfilesResponse;
+import com.google.bigtable.admin.v2.ListClustersRequest;
+import com.google.bigtable.admin.v2.ListClustersResponse;
+import com.google.bigtable.admin.v2.ListInstancesRequest;
+import com.google.bigtable.admin.v2.ListInstancesResponse;
+import com.google.bigtable.admin.v2.PartialUpdateInstanceRequest;
+import com.google.bigtable.admin.v2.ProjectName;
+import com.google.bigtable.admin.v2.UpdateAppProfileMetadata;
+import com.google.bigtable.admin.v2.UpdateAppProfileRequest;
+import com.google.bigtable.admin.v2.UpdateClusterMetadata;
+import com.google.bigtable.admin.v2.UpdateInstanceMetadata;
+import com.google.cloud.bigtable.admin.v2.models.FailedLocationException;
+import com.google.cloud.bigtable.admin.v2.models.InstanceAdminRequests;
+import com.google.cloud.bigtable.admin.v2.models.InstanceAdminRequests.AppProfile;
+import com.google.cloud.bigtable.admin.v2.models.InstanceAdminRequests.AppProfile.UpdateAppProfile;
+import com.google.cloud.bigtable.admin.v2.models.InstanceAdminRequests.Cluster;
+import com.google.cloud.bigtable.admin.v2.models.InstanceAdminRequests.CreateInstance;
+import com.google.cloud.bigtable.admin.v2.models.InstanceAdminRequests.Instance;
+import com.google.cloud.bigtable.admin.v2.models.InstanceAdminRequests.Policy;
+import com.google.cloud.bigtable.admin.v2.models.InstanceAdminRequests.UpdateCluster;
+import com.google.cloud.bigtable.admin.v2.models.InstanceAdminRequests.UpdateInstance;
+import com.google.cloud.bigtable.admin.v2.stub.BigtableInstanceAdminStub;
+import com.google.cloud.bigtable.admin.v2.stub.BigtableInstanceAdminStubSettings;
+import com.google.common.util.concurrent.MoreExecutors;
+import com.google.iam.v1.GetIamPolicyRequest;
+import com.google.iam.v1.SetIamPolicyRequest;
+import com.google.iam.v1.TestIamPermissionsRequest;
+
+@BetaApi
+public class InstanceAdminClient implements AutoCloseable {
+ private final BigtableInstanceAdminStub stub;
+
+ public static final InstanceAdminClient create() throws IOException {
+ return new InstanceAdminClient(BigtableInstanceAdminSettings.newBuilder().build());
+ }
+
+ public static final InstanceAdminClient create(BigtableInstanceAdminSettings settings)
+ throws IOException {
+ return new InstanceAdminClient(settings);
+ }
+
+ public static final InstanceAdminClient create(BigtableInstanceAdminStub stub) {
+ return new InstanceAdminClient(stub);
+ }
+
+ public InstanceAdminClient(BigtableInstanceAdminSettings settings) throws IOException {
+ this(((BigtableInstanceAdminStubSettings) settings.getStubSettings()).createStub());
+ }
+
+ public InstanceAdminClient(BigtableInstanceAdminStub stub) {
+ this.stub = stub;
+ }
+
+ @Override
+ public void close() throws Exception {
+ stub.close();
+ }
+
+ /**
+ *
+ *
+ * {@code
+ * try(InstanceAdminClient instanceAdmin = InstanceAdminClient.create()) {
+ * CreateInstance request =
+ * InstanceAdminRequests.createInstance(
+ * ProjectName.of("project"),
+ * Instance.ofNewProdInstance("instanceid", "displayname"),
+ * Cluster.ofNewProdCluster(
+ * "clusterone", Location.of("project", "zone"), 3))
+ * .addCluster(
+ * Cluster.ofNewProdCluster(
+ * "clustertwo", Location.of("project", "us-east1-c"), 4));
+ *
+ * Instance createdInstance = instanceAdmin.createInstanceAsync(request).get();
+ * }
+ * }
+ *
+ *
+ * @param createInstance
+ * @return
+ */
+ public ApiFuture createInstanceAsync(CreateInstance createInstance) {
+ final OperationFuture future =
+ stub.createInstanceOperationCallable().futureCall(createInstance.toProto());
+
+ return transfromOperationFuture(future,
+ new ApiFunction() {
+ @Override
+ public Instance apply(com.google.bigtable.admin.v2.Instance input) {
+ return InstanceAdminRequests.convertToInstance(input);
+ }
+ });
+ }
+
+ public Instance getInstance(InstanceName instanceName) {
+ return InstanceAdminRequests.convertToInstance(
+ stub.getInstanceCallable().call(composeGetInstanceRequest(instanceName)));
+ }
+
+ public List listInstances(ProjectName projectName) {
+ return convertToInstances(
+ stub.listInstancesCallable().call(composeListInstanceRequest(projectName)));
+ }
+
+ /**
+ *
+ *
+ * {@code
+ * try(InstanceAdminClient instanceAdmin = InstanceAdminClient.create()) {
+ * Instance devInstance = instanceAdmin.getInstance(
+ * InstanceName.of("project", "instance"));
+ *
+ * instanceAdmin.updateInstance(
+ * Instance.ofUpdateInstance(devInstance)
+ * .updateDisplayName("display")
+ * .upgradeType()
+ * .updateLabels(updatedLabels));
+ * }
+ * }
+ *
+ *
+ * @param updatedInstance
+ * @return
+ */
+ public ApiFuture updateInstance(UpdateInstance updatedInstance) {
+ OperationFuture future =
+ stub.partialUpdateInstanceOperationCallable()
+ .futureCall(composePartialUpdateInstanceCallable(updatedInstance));
+
+ return transfromOperationFuture(future,
+ new ApiFunction() {
+ @Override
+ public Instance apply(com.google.bigtable.admin.v2.Instance input) {
+ return InstanceAdminRequests.convertToInstance(input);
+ }
+ });
+ }
+
+ public void deleteInstanceRequest(InstanceName instanceName) {
+ stub.deleteInstanceCallable().call(composeDeleteInstanceRequest(instanceName));
+ }
+
+ public ApiFuture createCluster(InstanceName instanceName, Cluster cluster) {
+ OperationFuture future =
+ stub.createClusterOperationCallable()
+ .futureCall(composeCreateClusterRequest(instanceName, cluster));
+
+ return transfromOperationFuture(future,
+ new ApiFunction() {
+ @Override
+ public Cluster apply(com.google.bigtable.admin.v2.Cluster input) {
+ return InstanceAdminRequests.convertToCluster(input);
+ }
+ });
+ }
+
+ public Cluster getCluster(ClusterName clusterName) {
+ return InstanceAdminRequests.convertToCluster(
+ stub.getClusterCallable().call(composeGetClusterRequest(clusterName)));
+ }
+
+ public List listClusters(InstanceName instanceName) {
+ return convertToClusters(
+ stub.listClustersCallable().call(composeListClustersRequest(instanceName)));
+ }
+
+ /**
+ *
+ *
+ * {@code
+ * try(InstanceAdminClient instanceAdmin = InstanceAdminClient.create()) {
+ * Cluster prodCluster = instanceAdmin.getCluster(
+ * ClusterName.of("project", "instance", "cluster"));
+ *
+ * instanceAdmin.updateCluster(
+ * Cluster.ofUpdateCluster(prodCluster)
+ * .updateNumNodes(5));
+ * }
+ * }
+ *
+ *
+ * @param updatedCluster
+ * @return
+ */
+ public ApiFuture updateCluster(UpdateCluster updatedCluster) {
+ OperationFuture future =
+ stub.updateClusterOperationCallable().futureCall(updatedCluster.toProto());
+
+ return transfromOperationFuture(future,
+ new ApiFunction() {
+ @Override
+ public Cluster apply(com.google.bigtable.admin.v2.Cluster input) {
+ return InstanceAdminRequests.convertToCluster(input);
+ }
+ });
+ }
+
+ public void deleteCluster(ClusterName clusterName) {
+ stub.deleteClusterCallable().call(composeDeleteClusterRequest(clusterName));
+ }
+
+ /**
+ *
+ *
+ * {@code
+ * try(InstanceAdminClient instanceAdmin = InstanceAdminClient.create()) {
+ * instanceAdmin.createAppProfile(
+ * InstanceName.of("project", "instance"),
+ * AppProfile.ofNewAppProfile("roundRobin")
+ * .routeToAny());
+ * }
+ * }
+ *
+ *
+ * @param instanceName
+ * @param appProfile
+ * @return
+ */
+ public AppProfile createAppProfile(InstanceName instanceName, AppProfile appProfile) {
+ return InstanceAdminRequests.convertToAppProfile(stub.createAppProfileCallable().call(
+ composeCreateAppProfileRequest(instanceName, appProfile)));
+ }
+
+ public AppProfile getAppProfile(AppProfileName appProfileName) {
+ return InstanceAdminRequests.convertToAppProfile(
+ stub.getAppProfileCallable().call(composeGetAppProfileRequest(appProfileName)));
+ }
+
+ public List listAppProfiles(InstanceName instanceName) {
+ return convertToAppProfiles(
+ stub.listAppProfilesCallable().call(composeListAppProfilesRequest(instanceName)));
+ }
+
+ /**
+ *
+ *
+ * {@code
+ * try(InstanceAdminClient instanceAdmin = InstanceAdminClient.create()) {
+ * AppProfile appProfileAny = instanceAdmin.getAppProfile(
+ * AppProfileName.of("project", "instance", "profile"));
+ *
+ * AppProfile appProfileCluster = instanceAdmin.updateAppProfile(
+ * AppProfile.ofUpdateAppProfile(appProfileAny)
+ * .updateDescription("newDescription")
+ * .updateRouteToCluster("clusterToUse", false))
+ * .get();
+ * }
+ * }
+ *
+ *
+ * @param updateAppProfile
+ * @return
+ */
+ public ApiFuture updateAppProfile(UpdateAppProfile updateAppProfile) {
+ OperationFuture future =
+ stub.updateAppProfileOperationCallable()
+ .futureCall(composeUpdateAppProfileRequest(updateAppProfile));
+
+ return transfromOperationFuture(future,
+ new ApiFunction() {
+ @Override
+ public AppProfile apply(com.google.bigtable.admin.v2.AppProfile input) {
+ return InstanceAdminRequests.convertToAppProfile(input);
+ }
+ });
+ }
+
+ public void deleteAppProfile(AppProfileName appProfileName, boolean ignoreWarnings) {
+ stub.deleteAppProfileCallable()
+ .call(composeDeleteAppProfileRequest(appProfileName, ignoreWarnings));
+ }
+
+ public Policy getIamPolicy(InstanceName instanceName) {
+ return InstanceAdminRequests.convertToPolicy(
+ stub.getIamPolicyCallable().call(composeGetIamPolicyRequest(instanceName)));
+ }
+
+ public Policy setIamPolicy(InstanceName instanceName, Policy policy) {
+ return InstanceAdminRequests.convertToPolicy(
+ stub.setIamPolicyCallable().call(composeSetIamPolicyRequest(instanceName, policy)));
+ }
+
+ public List testIamPermissions(InstanceName instanceName, List permissions) {
+ return stub.testIamPermissionsCallable()
+ .call(composeTestIamPermissionsRequest(instanceName, permissions))
+ .getPermissionsList();
+ }
+
+ /** compose proto request helpers * */
+ private static GetInstanceRequest composeGetInstanceRequest(InstanceName instanceName) {
+ return GetInstanceRequest.newBuilder().setName(instanceName.toString()).build();
+ }
+
+ private static ListInstancesRequest composeListInstanceRequest(ProjectName projectName) {
+ return ListInstancesRequest.newBuilder().setParent(projectName.toString()).build();
+ }
+
+ private static PartialUpdateInstanceRequest composePartialUpdateInstanceCallable(
+ UpdateInstance updatedInstance) {
+ return PartialUpdateInstanceRequest.newBuilder().setInstance(updatedInstance.toProto())
+ .setUpdateMask(updatedInstance.getPartialUpdateFieldMask())
+ .build();
+ }
+
+ private static DeleteInstanceRequest composeDeleteInstanceRequest(InstanceName instanceName) {
+ return DeleteInstanceRequest.newBuilder().setName(instanceName.toString()).build();
+ }
+
+ private static CreateClusterRequest composeCreateClusterRequest(InstanceName instanceName,
+ Cluster cluster) {
+ return CreateClusterRequest.newBuilder().setParent(instanceName.toString())
+ .setClusterId(cluster.getId()).setCluster(cluster.toProto()).build();
+ }
+
+ private static GetClusterRequest composeGetClusterRequest(ClusterName clusterName) {
+ return GetClusterRequest.newBuilder().setName(clusterName.toString()).build();
+ }
+
+ private static ListClustersRequest composeListClustersRequest(InstanceName instanceName) {
+ return ListClustersRequest.newBuilder().setParent(instanceName.toString()).build();
+ }
+
+ private static DeleteClusterRequest composeDeleteClusterRequest(ClusterName clusterName) {
+ return DeleteClusterRequest.newBuilder().setName(clusterName.toString()).build();
+ }
+
+ private static CreateAppProfileRequest composeCreateAppProfileRequest(InstanceName instanceName,
+ AppProfile appProfile) {
+ return CreateAppProfileRequest.newBuilder().setParent(instanceName.toString())
+ .setAppProfileId(appProfile.getId())
+ .setAppProfile(appProfile.toProto()).build();
+ }
+
+ private static GetAppProfileRequest composeGetAppProfileRequest(AppProfileName appProfileName) {
+ return GetAppProfileRequest.newBuilder().setName(appProfileName.toString()).build();
+ }
+
+ private static ListAppProfilesRequest composeListAppProfilesRequest(InstanceName instanceName) {
+ return ListAppProfilesRequest.newBuilder().setParent(instanceName.toString()).build();
+ }
+
+ private static UpdateAppProfileRequest composeUpdateAppProfileRequest(
+ UpdateAppProfile updateAppProfile) {
+ return UpdateAppProfileRequest.newBuilder().setAppProfile(updateAppProfile.toProto())
+ .setUpdateMask(updateAppProfile.getPartialUpdateFieldMask())
+ .build();
+ }
+
+ private static DeleteAppProfileRequest composeDeleteAppProfileRequest(
+ AppProfileName appProfileName, boolean ignoreWarnings) {
+ return DeleteAppProfileRequest.newBuilder().setName(appProfileName.toString())
+ .setIgnoreWarnings(ignoreWarnings).build();
+ }
+
+ private static GetIamPolicyRequest composeGetIamPolicyRequest(InstanceName instanceName) {
+ return GetIamPolicyRequest.newBuilder().setResource(instanceName.toString()).build();
+ }
+
+ private static SetIamPolicyRequest composeSetIamPolicyRequest(InstanceName instanceName,
+ Policy policy) {
+ return SetIamPolicyRequest.newBuilder().setResource(instanceName.toString())
+ .setPolicy(policy.toProto()).build();
+ }
+
+ private static TestIamPermissionsRequest composeTestIamPermissionsRequest(
+ InstanceName instanceName, List permissions) {
+ return TestIamPermissionsRequest.newBuilder().setResource(instanceName.toString())
+ .addAllPermissions(permissions).build();
+ }
+
+ private static List convertToInstances(ListInstancesResponse listInstancesResponse) {
+ List instances = new ArrayList<>();
+ List succeededLocations = new ArrayList<>();
+ for (com.google.bigtable.admin.v2.Instance instance : listInstancesResponse.getInstancesList()) {
+ instances.add(InstanceAdminRequests.convertToInstance(instance));
+ }
+
+ if (listInstancesResponse.getFailedLocationsList().size() > 0) {
+ throw new FailedLocationException("Failed to list all locations", succeededLocations,
+ listInstancesResponse.getFailedLocationsList());
+ }
+
+ return instances;
+ }
+
+ private static List convertToClusters(ListClustersResponse listClustersResponse) {
+ List clusters = new ArrayList<>();
+ List succeededLocations = new ArrayList<>();
+ for (com.google.bigtable.admin.v2.Cluster cluster : listClustersResponse.getClustersList()) {
+ clusters.add(InstanceAdminRequests.convertToCluster(cluster));
+ succeededLocations.add(cluster.getLocation());
+ }
+
+ if (listClustersResponse.getFailedLocationsList().size() > 0) {
+ throw new FailedLocationException("Failed to list all locations", succeededLocations,
+ listClustersResponse.getFailedLocationsList());
+ }
+
+ return clusters;
+ }
+
+ private static List convertToAppProfiles(
+ ListAppProfilesResponse listAppProfilesResponse) {
+ List appProfiles = new ArrayList<>();
+
+ for (com.google.bigtable.admin.v2.AppProfile profile : listAppProfilesResponse.getAppProfilesList()) {
+ appProfiles.add(InstanceAdminRequests.convertToAppProfile(profile));
+ }
+ return appProfiles;
+ }
+
+ /** Can be removed after https://github.com/googleapis/gax-java/issues/552 is handled */
+ private static ApiFuture transfromOperationFuture(
+ final OperationFuture extends V, M> future,
+ final ApiFunction super V, ? extends X> function) {
+ final SettableApiFuture result = SettableApiFuture.create();
+ future.addListener(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ result.set(function.apply(future.get()));
+ } catch (InterruptedException | ExecutionException e) {
+ result.setException(e);
+ }
+ }
+ }, MoreExecutors.directExecutor());
+ return result;
+ }
+}
diff --git a/google-cloud-clients/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/models/FailedLocationException.java b/google-cloud-clients/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/models/FailedLocationException.java
new file mode 100644
index 000000000000..cfc62e44a516
--- /dev/null
+++ b/google-cloud-clients/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/models/FailedLocationException.java
@@ -0,0 +1,26 @@
+package com.google.cloud.bigtable.admin.v2.models;
+
+import java.util.List;
+import com.google.api.core.BetaApi;
+
+@BetaApi
+public class FailedLocationException extends RuntimeException {
+ private static final long serialVersionUID = 1L;
+ private final List succeededLocations;
+ private final List failedLocations;
+
+ public FailedLocationException(
+ String message, List succeededLocations, List failedLocations) {
+ super(message);
+ this.succeededLocations = succeededLocations;
+ this.failedLocations = failedLocations;
+ }
+
+ public List getSucceededLocations() {
+ return succeededLocations;
+ }
+
+ public List getFailedLocations() {
+ return failedLocations;
+ }
+}
diff --git a/google-cloud-clients/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/models/InstanceAdminRequests.java b/google-cloud-clients/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/models/InstanceAdminRequests.java
new file mode 100644
index 000000000000..6d598e70ef82
--- /dev/null
+++ b/google-cloud-clients/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/models/InstanceAdminRequests.java
@@ -0,0 +1,585 @@
+package com.google.cloud.bigtable.admin.v2.models;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import com.google.api.core.BetaApi;
+import com.google.api.core.InternalApi;
+import com.google.bigtable.admin.v2.AppProfile.RoutingPolicyCase;
+import com.google.bigtable.admin.v2.AppProfileName;
+import com.google.bigtable.admin.v2.ClusterName;
+import com.google.bigtable.admin.v2.CreateInstanceRequest;
+import com.google.bigtable.admin.v2.Instance.State;
+import com.google.bigtable.admin.v2.Instance.Type;
+import com.google.bigtable.admin.v2.InstanceName;
+import com.google.bigtable.admin.v2.ProjectName;
+import com.google.bigtable.admin.v2.StorageType;
+import com.google.cloud.Role;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Preconditions;
+import com.google.iam.v1.Binding;
+import com.google.protobuf.ByteString;
+import com.google.protobuf.FieldMask;
+
+@BetaApi
+public final class InstanceAdminRequests {
+
+ public static CreateInstance createInstance(
+ ProjectName projectName, Instance instance, Cluster cluster) {
+ return new CreateInstance(projectName, instance, cluster);
+ }
+
+ public static Instance convertToInstance(com.google.bigtable.admin.v2.Instance protoInstance) {
+ return new Instance(protoInstance);
+ }
+
+ public static Cluster convertToCluster(com.google.bigtable.admin.v2.Cluster protoCluster) {
+ return new Cluster(protoCluster);
+ }
+
+ public static AppProfile convertToAppProfile(com.google.bigtable.admin.v2.AppProfile appProfile) {
+ return new AppProfile(appProfile);
+ }
+
+ public static Policy convertToPolicy(com.google.iam.v1.Policy policy) {
+ return new Policy(policy);
+ }
+
+ /** */
+ public static final class CreateInstance {
+ private final CreateInstanceRequest.Builder createInstanceRequest =
+ CreateInstanceRequest.newBuilder();
+
+ private CreateInstance(ProjectName projectName, Instance instance, Cluster cluster) {
+ Preconditions.checkNotNull(projectName);
+ Preconditions.checkNotNull(instance);
+ Preconditions.checkNotNull(cluster);
+
+ createInstanceRequest
+ .setParent(projectName.toString())
+ .setInstanceId(instance.getid())
+ .setInstance(instance.toProto())
+ .putClusters(cluster.getId(), cluster.toProto());
+ }
+
+ public CreateInstance addCluster(Cluster cluster) {
+ createInstanceRequest.putClusters(cluster.getId(), cluster.toProto());
+ return this;
+ }
+
+ public CreateInstanceRequest toProto() {
+ return createInstanceRequest.build();
+ }
+ }
+
+ public static final class Instance {
+ private final String id;
+ private com.google.bigtable.admin.v2.Instance.Builder protoInstance =
+ com.google.bigtable.admin.v2.Instance.newBuilder();
+
+ public static Instance ofNewDevInstance(String instanceId, String displayName) {
+ return new Instance(instanceId, displayName, Type.DEVELOPMENT);
+ }
+
+ public static Instance ofNewProdInstance(String instanceId, String displayName) {
+ return new Instance(instanceId, displayName, Type.PRODUCTION);
+ }
+
+ public static UpdateInstance ofUpdateInstance(Instance instance) {
+ return new UpdateInstance(instance);
+ }
+
+ private Instance(String instanceId, String displayName, Type instanceType) {
+ this.id = instanceId;
+ protoInstance.setDisplayName(displayName).setType(instanceType);
+ }
+
+ private Instance(com.google.bigtable.admin.v2.Instance instance) {
+ this.protoInstance = instance.toBuilder();
+ id = getName().getInstance();
+ }
+
+ public String getid() {
+ return id;
+ }
+
+ public InstanceName getName() {
+ return InstanceName.parse(protoInstance.getName());
+ }
+
+ public String getDisplayName() {
+ return protoInstance.getDisplayName();
+ }
+
+ public State getState() {
+ return protoInstance.getState();
+ }
+
+ public Type getType() {
+ return protoInstance.getType();
+ }
+
+ public Map getLabelsMap() {
+ return protoInstance.getLabelsMap();
+ }
+
+ public Instance addLabel(String key, String value) {
+ // TODO: add an regex check. Error from is hard to decipher
+ protoInstance.putLabels(key, value);
+ return this;
+ }
+
+ @InternalApi
+ public com.google.bigtable.admin.v2.Instance toProto() {
+ return protoInstance.build();
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this)
+ .add("name", getName())
+ .add("displayName", getDisplayName())
+ .add("state", getState())
+ .add("type", getType())
+ .add("labels", getLabelsMap())
+ .toString();
+ }
+ }
+
+ public static final class UpdateInstance {
+ private final String DISPLAY_NAME_FIELDMASK = "display_name";
+ private final String TYPE_FIELDMASK = "type";
+ private final String LABELS_FIELDMASK = "labels";
+
+ private final List replacefields = new ArrayList<>();
+ private com.google.bigtable.admin.v2.Instance.Builder protoUpdateInstance =
+ com.google.bigtable.admin.v2.Instance.newBuilder();
+
+ private UpdateInstance(Instance instance) {
+ protoUpdateInstance = instance.toProto().toBuilder().clone();
+ }
+
+ public UpdateInstance updateDisplayName(String updatedDisplayName) {
+ replacefields.add(DISPLAY_NAME_FIELDMASK);
+ protoUpdateInstance.setDisplayName(updatedDisplayName);
+ return this;
+ }
+
+ public UpdateInstance upgradeType() {
+ Preconditions.checkArgument(
+ Type.DEVELOPMENT.equals(protoUpdateInstance.getType()),
+ "PRODUCTION type cannot be upgraded");
+ replacefields.add(TYPE_FIELDMASK);
+ protoUpdateInstance.setType(Type.PRODUCTION);
+ return this;
+ }
+
+ public UpdateInstance updateLabels(Map updatedLabels) {
+ replacefields.add(LABELS_FIELDMASK);
+ protoUpdateInstance.putAllLabels(updatedLabels);
+ return this;
+ }
+
+ @InternalApi
+ public com.google.bigtable.admin.v2.Instance toProto() {
+ return protoUpdateInstance.clearState().build();
+ }
+
+ @InternalApi
+ public FieldMask getPartialUpdateFieldMask() {
+ return FieldMask.newBuilder().addAllPaths(replacefields).build();
+ }
+ }
+
+ public static final class Cluster {
+ public static Cluster ofNewDevCluster(String clusterId, Location location) {
+ return new Cluster(clusterId, location, 0);
+ }
+
+ public static Cluster ofNewProdCluster(String clusterId, Location location, int serverNodes) {
+ return new Cluster(clusterId, location, serverNodes);
+ }
+
+ public static UpdateCluster ofUpdateCluster(Cluster cluster) {
+ return new UpdateCluster(cluster);
+ }
+
+ private final String id;
+ private com.google.bigtable.admin.v2.Cluster.Builder protoCluster =
+ com.google.bigtable.admin.v2.Cluster.newBuilder();
+
+ private Cluster(String clusterId, Location location, int serverNodes) {
+ protoCluster.setLocation(location.toString()).setServeNodes(serverNodes);
+ this.id = clusterId;
+ }
+
+ private Cluster(com.google.bigtable.admin.v2.Cluster cluster) {
+ protoCluster = cluster.toBuilder();
+ id = getName().getCluster();
+ }
+
+ public Cluster setDefaultStorage(StorageType defaultStorage) {
+ protoCluster.setDefaultStorageType(defaultStorage);
+ return this;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public ClusterName getName() {
+ return ClusterName.parse(protoCluster.getName());
+ }
+
+ public String getLocation() {
+ return protoCluster.getLocation();
+ }
+
+ public com.google.bigtable.admin.v2.Cluster.State getState() {
+ return protoCluster.getState();
+ }
+
+ public int getServerNodes() {
+ return protoCluster.getServeNodes();
+ }
+
+ public StorageType getDefaultStorageType() {
+ return protoCluster.getDefaultStorageType();
+ }
+
+ @InternalApi
+ public com.google.bigtable.admin.v2.Cluster toProto() {
+ // TODO: defaultStorage is currently optional, should we make this required?
+ return protoCluster.build();
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this)
+ .add("name", getName())
+ .add("location", getLocation())
+ .add("state", getState())
+ .add("serverNodes", getServerNodes())
+ .add("defaultStorageType", getDefaultStorageType())
+ .toString();
+ }
+ }
+
+ public static final class UpdateCluster {
+ private com.google.bigtable.admin.v2.Cluster.Builder protoUpdateCluster =
+ com.google.bigtable.admin.v2.Cluster.newBuilder();
+
+ private UpdateCluster(Cluster cluster) {
+ protoUpdateCluster = cluster.toProto().toBuilder().clone();
+ }
+
+ public UpdateCluster updateNumNodes(int serverNodes) {
+ protoUpdateCluster.setServeNodes(serverNodes);
+ return this;
+ }
+
+ @InternalApi
+ public com.google.bigtable.admin.v2.Cluster toProto() {
+ return protoUpdateCluster.clearState().clearDefaultStorageType().build();
+ }
+ }
+
+ public static final class AppProfile {
+ private final String id;
+ private com.google.bigtable.admin.v2.AppProfile.Builder protoProfile =
+ com.google.bigtable.admin.v2.AppProfile.newBuilder();
+
+ public static AppProfile ofNewAppProfile(String profileId) {
+ return new AppProfile(profileId);
+ }
+
+ public static UpdateAppProfile ofUpdateAppProfile(AppProfile appProfile) {
+ return new UpdateAppProfile(appProfile);
+ }
+
+ private AppProfile(String profileId) {
+ id = profileId;
+ }
+
+ private AppProfile(com.google.bigtable.admin.v2.AppProfile appProfile) {
+ protoProfile = appProfile.toBuilder();
+ id = getName().getAppProfile();
+ }
+
+ public AppProfile setDescription(String description) {
+ protoProfile.setDescription(description);
+ return this;
+ }
+
+ public AppProfile routeToAny() {
+ protoProfile.setMultiClusterRoutingUseAny(
+ com.google.bigtable.admin.v2.AppProfile.MultiClusterRoutingUseAny.newBuilder().build());
+ protoProfile.clearSingleClusterRouting();
+ return this;
+ }
+
+ public AppProfile routeToCluster(String clusterId, boolean ignoreWarnings) {
+ protoProfile.setSingleClusterRouting(
+ com.google.bigtable.admin.v2.AppProfile.SingleClusterRouting.newBuilder()
+ .setClusterId(clusterId)
+ .setAllowTransactionalWrites(ignoreWarnings));
+ protoProfile.clearMultiClusterRoutingUseAny();
+ return this;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public AppProfileName getName() {
+ return AppProfileName.parse(protoProfile.getName());
+ }
+
+ public String getEtag() {
+ return protoProfile.getEtag();
+ }
+
+ public String getDescription() {
+ return protoProfile.getDescription();
+ }
+
+ public RoutingPolicy getRoutingPolicy() {
+ if (RoutingPolicyCase.MULTI_CLUSTER_ROUTING_USE_ANY
+ .name()
+ .equals(protoProfile.getRoutingPolicyCase().name())) {
+ return new MultiClusterRoutingUseAny();
+ }
+
+ if (RoutingPolicyCase.SINGLE_CLUSTER_ROUTING
+ .name()
+ .equals(protoProfile.getRoutingPolicyCase().name())) {
+ return new SingleClusterRouting(protoProfile.getSingleClusterRouting());
+ }
+
+ return new RoutingPolicyNotSet();
+ }
+
+ @InternalApi
+ public com.google.bigtable.admin.v2.AppProfile toProto() {
+ // TODO: should we default this to any instead?
+ Preconditions.checkState(
+ protoProfile.hasMultiClusterRoutingUseAny() || protoProfile.hasSingleClusterRouting(),
+ "Must specify a routing option");
+ return protoProfile.build();
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this)
+ .add("name", getName())
+ .add("etag", getEtag())
+ .add("description", getDescription())
+ .add("routingPolicy", getRoutingPolicy())
+ .toString();
+ }
+
+ public static class UpdateAppProfile {
+ private static final String DESCRIPTION_FIELDMASK = "description";
+ private static final String MULTI_CLUSTER_FIELDMASK = "multi_cluster_routing_use_any";
+ private static final String SINGLE_CLUSTER__FIELDMASK = "single_cluster_routing";
+
+ private final List replacefields = new ArrayList<>();
+ private com.google.bigtable.admin.v2.AppProfile.Builder protoUpdateProfile =
+ com.google.bigtable.admin.v2.AppProfile.newBuilder();
+
+ private UpdateAppProfile(AppProfile appProfile) {
+ Preconditions.checkNotNull(appProfile);
+ protoUpdateProfile = appProfile.toProto().toBuilder().clone();
+ }
+
+ public UpdateAppProfile updateDescription(String updatedDescription) {
+ replacefields.add(DESCRIPTION_FIELDMASK);
+ protoUpdateProfile.setDescription(updatedDescription);
+ return this;
+ }
+
+ public UpdateAppProfile updateRouteToAny() {
+ protoUpdateProfile.setMultiClusterRoutingUseAny(
+ com.google.bigtable.admin.v2.AppProfile.MultiClusterRoutingUseAny.newBuilder().build());
+ protoUpdateProfile.clearSingleClusterRouting();
+ replacefields.add(MULTI_CLUSTER_FIELDMASK);
+ return this;
+ }
+
+ public UpdateAppProfile updateRouteToCluster(String clusterId, boolean ignoreWarnings) {
+ protoUpdateProfile.setSingleClusterRouting(
+ com.google.bigtable.admin.v2.AppProfile.SingleClusterRouting.newBuilder()
+ .setClusterId(clusterId)
+ .setAllowTransactionalWrites(ignoreWarnings));
+ protoUpdateProfile.clearMultiClusterRoutingUseAny();
+ replacefields.add(SINGLE_CLUSTER__FIELDMASK);
+ return this;
+ }
+
+ @InternalApi
+ public com.google.bigtable.admin.v2.AppProfile toProto() {
+ return protoUpdateProfile.build();
+ }
+
+ @InternalApi
+ public FieldMask getPartialUpdateFieldMask() {
+ return FieldMask.newBuilder().addAllPaths(replacefields).build();
+ }
+ }
+
+ public interface RoutingPolicy {
+ RoutingPolicyCase name();
+ }
+
+ public static class RoutingPolicyNotSet implements RoutingPolicy {
+ private RoutingPolicyNotSet() {}
+
+ @Override
+ public RoutingPolicyCase name() {
+ return RoutingPolicyCase.ROUTINGPOLICY_NOT_SET;
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this).add("name", name()).toString();
+ }
+ }
+
+ public static class MultiClusterRoutingUseAny implements RoutingPolicy {
+ private MultiClusterRoutingUseAny() {}
+
+ @Override
+ public RoutingPolicyCase name() {
+ return RoutingPolicyCase.MULTI_CLUSTER_ROUTING_USE_ANY;
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this).add("name", name()).toString();
+ }
+ }
+
+ public static class SingleClusterRouting implements RoutingPolicy {
+ private final String clusterId;
+ private final boolean allowTransactionalWrites;
+
+ private SingleClusterRouting(String clusterId, boolean allowTransactionalWrites) {
+ this.clusterId = clusterId;
+ this.allowTransactionalWrites = allowTransactionalWrites;
+ }
+
+ private SingleClusterRouting(
+ com.google.bigtable.admin.v2.AppProfile.SingleClusterRouting routing) {
+ this.clusterId = routing.getClusterId();
+ this.allowTransactionalWrites = routing.getAllowTransactionalWrites();
+ }
+
+ public String getClusterId() {
+ return clusterId;
+ }
+
+ public boolean isAllowTransactionalWrites() {
+ return allowTransactionalWrites;
+ }
+
+ @Override
+ public RoutingPolicyCase name() {
+ return RoutingPolicyCase.SINGLE_CLUSTER_ROUTING;
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this)
+ .add("name", name())
+ .add("clusterId", getClusterId())
+ .add("allowTransactionalWrites", isAllowTransactionalWrites())
+ .toString();
+ }
+ }
+ }
+
+ public static final class Policy {
+ private com.google.iam.v1.Policy.Builder protoPolicy = com.google.iam.v1.Policy.newBuilder();
+
+ public static Policy of(int version, Role role, List members) {
+ return new Policy(version, role, members);
+ }
+
+ private Policy(int version, Role role, List members) {
+ Preconditions.checkNotNull(role);
+ Preconditions.checkNotNull(members);
+
+ protoPolicy.setVersion(version);
+ addRole(role, members);
+ }
+
+ private Policy(com.google.iam.v1.Policy policy) {
+ protoPolicy = policy.toBuilder();
+ }
+
+ public Policy addRole(Role role, List members) {
+ Preconditions.checkNotNull(role);
+ Preconditions.checkNotNull(members);
+
+ protoPolicy.addBindings(
+ com.google.iam.v1.Binding.newBuilder().setRole(role.toString()).addAllMembers(members));
+ return this;
+ }
+
+ public int getVersion() {
+ return protoPolicy.getVersion();
+ }
+
+ public ByteString getEtag() {
+ return protoPolicy.getEtag();
+ }
+
+ public Map> getBindingsMap() {
+ Map> bindings = new HashMap<>();
+
+ for (Binding binding : protoPolicy.getBindingsList()) {
+ bindings.put(Role.of(binding.getRole()), binding.getMembersList());
+ }
+ return bindings;
+ }
+
+ @InternalApi
+ public com.google.iam.v1.Policy toProto() {
+ return protoPolicy.build();
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this)
+ .add("version", getVersion())
+ .add("etag", getEtag())
+ .add("bindingsMap", getBindingsMap())
+ .toString();
+ }
+ }
+
+ public static final class Location {
+ public static Location of(String project, String zone) {
+ return new Location(project, zone);
+ }
+
+ private final String location;
+
+ private Location(String project, String zone) {
+ Preconditions.checkNotNull(project);
+ Preconditions.checkNotNull(zone);
+
+ location =
+ new StringBuilder(ProjectName.of(project).toString())
+ .append("/locations/")
+ .append(zone)
+ .toString();
+ }
+
+ @Override
+ public String toString() {
+ return location;
+ }
+ }
+}
diff --git a/google-cloud-clients/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/it/InstanceAdminClientIT.java b/google-cloud-clients/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/it/InstanceAdminClientIT.java
new file mode 100644
index 000000000000..54517334aac6
--- /dev/null
+++ b/google-cloud-clients/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/it/InstanceAdminClientIT.java
@@ -0,0 +1,351 @@
+package com.google.cloud.bigtable.admin.v2.it;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import com.google.bigtable.admin.v2.AppProfile.RoutingPolicyCase;
+import com.google.bigtable.admin.v2.AppProfileName;
+import com.google.bigtable.admin.v2.ClusterName;
+import com.google.bigtable.admin.v2.Instance.State;
+import com.google.bigtable.admin.v2.Instance.Type;
+import com.google.bigtable.admin.v2.InstanceName;
+import com.google.bigtable.admin.v2.ProjectName;
+import com.google.bigtable.admin.v2.StorageType;
+import com.google.cloud.bigtable.admin.v2.InstanceAdminClient;
+import com.google.cloud.bigtable.admin.v2.models.InstanceAdminRequests;
+import com.google.cloud.bigtable.admin.v2.models.InstanceAdminRequests.AppProfile;
+import com.google.cloud.bigtable.admin.v2.models.InstanceAdminRequests.Cluster;
+import com.google.cloud.bigtable.admin.v2.models.InstanceAdminRequests.CreateInstance;
+import com.google.cloud.bigtable.admin.v2.models.InstanceAdminRequests.Instance;
+import com.google.cloud.bigtable.admin.v2.models.InstanceAdminRequests.Location;
+import com.google.cloud.bigtable.admin.v2.models.InstanceAdminRequests.Policy;
+import com.google.common.collect.ImmutableMap;
+
+public class InstanceAdminClientIT {
+ private static InstanceAdminClient instanceAdmin;
+ private static final ProjectName TEST_PROJECT = ProjectName.of("sduskis-hello-shakespear");
+ private static final String TEST_PROD_INST_ID = "instadmprodtest";
+ private static final String TEST_DEV_INST_ID = "instadmdevtest";
+ private static final int PROD_CLUSTER_SIZE = 3;
+
+ @BeforeClass
+ public static void createClient() throws Exception {
+ instanceAdmin = InstanceAdminClient.create();
+ }
+
+ @AfterClass
+ public static void closeClient() throws Exception {
+ instanceAdmin.close();
+ }
+
+ @Test
+ public void createInstanceHarness() throws Exception {
+ Instance newProdInstance = Instance.ofNewProdInstance(TEST_PROD_INST_ID, "disp");
+
+ Cluster newCluster =
+ Cluster.ofNewProdCluster(
+ TEST_PROD_INST_ID + "us-east1-c",
+ Location.of(TEST_PROJECT.getProject(), "us-east1-c"),
+ PROD_CLUSTER_SIZE);
+
+ try {
+ // Instance tests
+ int numInstances = instanceAdmin.listInstances(TEST_PROJECT).size();
+ Instance createdInstance = createInstance(TEST_PROJECT, newProdInstance, newCluster);
+ listInstances(numInstances + 1);
+ getInstance(createdInstance);
+ updateInstance(createdInstance);
+ partialUpdateInstance(createdInstance);
+
+ // Cluster tests
+ getCluster(
+ newCluster,
+ ClusterName.of(TEST_PROJECT.getProject(), TEST_PROD_INST_ID, newCluster.getId()));
+ listClusters(createdInstance.getName(), 1);
+
+ Exception cannotMixClusterType = null;
+ try {
+ createCluster(
+ createdInstance,
+ Cluster.ofNewDevCluster(
+ TEST_DEV_INST_ID + "us-east1-d",
+ Location.of(TEST_PROJECT.getProject(), "us-east1-d")));
+ } catch (Exception ex) {
+ cannotMixClusterType = ex;
+ }
+ assertNotNull(cannotMixClusterType);
+
+ Cluster createdCluster2 =
+ createCluster(
+ createdInstance,
+ Cluster.ofNewProdCluster(
+ TEST_PROD_INST_ID + "us-east1-d",
+ Location.of(TEST_PROJECT.getProject(), "us-east1-d"),
+ PROD_CLUSTER_SIZE + 1));
+ getCluster(createdCluster2);
+ updateCluster(createdCluster2);
+ listClusters(createdInstance.getName(), 2);
+
+ // AppProfile tests
+ AppProfile createdAny =
+ createAppProfile(
+ createdInstance.getName(), AppProfile.ofNewAppProfile("roundRobin").routeToAny());
+ getAppProfile(createdAny);
+ updateAppProfileToSingle(createdAny, createdCluster2.getId());
+ listAppProfiles(createdInstance.getName(), 2); // +1 for default appProfile
+ deleteAppProfile(createdAny.getName());
+
+ // IamPolicy tests
+ // TODO: Needs Iam permissions to test this.
+ // Policy rawPolicy = Policy.of(1, Role.owner(),
+ // Arrays.asList("user:user@domain.com"));
+ // Policy actualPolicy = instanceAdmin.setIamPolicy(createdInstance.getName(), rawPolicy);
+
+ Policy iamPolicy = instanceAdmin.getIamPolicy(createdInstance.getName());
+ assertNotNull(iamPolicy);
+
+ List actualPermissions =
+ instanceAdmin.testIamPermissions(
+ createdInstance.getName(), Arrays.asList("bigtable.tables.checkConsistency"));
+ assertEquals(Arrays.asList("bigtable.tables.checkConsistency"), actualPermissions);
+
+ deleteCluster(createdCluster2);
+ listClusters(createdInstance.getName(), 1);
+ } finally {
+ instanceAdmin.deleteInstanceRequest(
+ InstanceName.of(TEST_PROJECT.getProject(), TEST_PROD_INST_ID));
+ }
+ }
+
+ @Test
+ public void createInstanceMultiCluster() throws Exception {
+ CreateInstance request =
+ InstanceAdminRequests.createInstance(
+ TEST_PROJECT,
+ Instance.ofNewProdInstance("multitest", "twoclusters"),
+ Cluster.ofNewProdCluster(
+ "clusterone", Location.of(TEST_PROJECT.getProject(), "us-east1-c"), 3))
+ .addCluster(
+ Cluster.ofNewProdCluster(
+ "clustertwo", Location.of(TEST_PROJECT.getProject(), "us-east1-c"), 4));
+
+ try {
+ Instance createdInstance = instanceAdmin.createInstanceAsync(request).get();
+ getInstance(createdInstance);
+ listClusters(createdInstance.getName(), 2);
+ } finally {
+ instanceAdmin.deleteInstanceRequest(InstanceName.of(TEST_PROJECT.getProject(), "multitest"));
+ }
+ }
+
+ @Test
+ public void createInstanceUpgradeHarness() throws Exception {
+ Instance newDevInstance =
+ Instance.ofNewDevInstance(TEST_DEV_INST_ID, TEST_DEV_INST_ID + "disp")
+ .addLabel("label_name_1", "label_value_1")
+ .addLabel("label_name_2", "label_value_2");
+
+ Cluster newDevCluster =
+ Cluster.ofNewDevCluster(
+ TEST_DEV_INST_ID + "us-east1-c", Location.of(TEST_PROJECT.getProject(), "us-east1-c"));
+ try {
+ Instance createdInstance =
+ instanceAdmin
+ .createInstanceAsync(
+ InstanceAdminRequests.createInstance(TEST_PROJECT, newDevInstance, newDevCluster))
+ .get();
+ assertInstanceEquals(newDevInstance, createdInstance);
+
+ listClusters(createdInstance.getName(), 1);
+ getCluster(
+ newDevCluster,
+ ClusterName.of(TEST_PROJECT.getProject(), TEST_DEV_INST_ID, newDevCluster.getId()));
+
+ Instance upgradedInstance =
+ instanceAdmin
+ .updateInstance(Instance.ofUpdateInstance(createdInstance).upgradeType())
+ .get();
+ assertEquals(Type.PRODUCTION, upgradedInstance.getType());
+ } finally {
+ instanceAdmin.deleteInstanceRequest(
+ InstanceName.of(TEST_PROJECT.getProject(), TEST_DEV_INST_ID));
+ }
+ }
+
+ /** helpers to execute and assert * */
+ private Instance createInstance(ProjectName projectName, Instance newInstance, Cluster newCluster)
+ throws Exception {
+ Instance actualInstance =
+ instanceAdmin
+ .createInstanceAsync(
+ InstanceAdminRequests.createInstance(projectName, newInstance, newCluster))
+ .get();
+ assertInstanceEquals(newInstance, actualInstance);
+ return actualInstance;
+ }
+
+ private void getInstance(Instance expected) {
+ Instance actual = instanceAdmin.getInstance(expected.getName());
+ assertThat(actual).isEqualTo(actual);
+ }
+
+ private void updateInstance(Instance instance) throws Exception {
+ Map updatedLabels = ImmutableMap.of("team", "team1", "subteam", "subteam1");
+ Instance updatedInstance =
+ instanceAdmin
+ .updateInstance(
+ Instance.ofUpdateInstance(instance)
+ .updateDisplayName(TEST_DEV_INST_ID + "upddisp")
+ .updateLabels(updatedLabels))
+ .get();
+
+ assertEquals(TEST_DEV_INST_ID + "upddisp", updatedInstance.getDisplayName());
+ assertEquals(updatedLabels, updatedInstance.getLabelsMap());
+ }
+
+ private void partialUpdateInstance(Instance instance) throws Exception {
+ Instance updatedInstance =
+ instanceAdmin
+ .updateInstance(
+ Instance.ofUpdateInstance(instance).updateDisplayName(TEST_PROD_INST_ID + "disp"))
+ .get();
+
+ assertEquals(TEST_PROD_INST_ID + "disp", updatedInstance.getDisplayName());
+ assertEquals(instance.getLabelsMap(), updatedInstance.getLabelsMap());
+ }
+
+ private void getCluster(Cluster raw, ClusterName clusterName) {
+ Cluster actual = instanceAdmin.getCluster(clusterName);
+ assertClusterEquals(raw, actual, clusterName);
+ }
+
+ private Cluster createCluster(Instance instance, Cluster rawCluster) throws Exception {
+ Cluster actual = instanceAdmin.createCluster(instance.getName(), rawCluster).get();
+ assertClusterEquals(
+ rawCluster,
+ actual,
+ ClusterName.of(
+ instance.getName().getProject(), instance.getName().getInstance(), rawCluster.getId()));
+ return actual;
+ }
+
+ private void getCluster(Cluster expected) {
+ Cluster actual = instanceAdmin.getCluster(expected.getName());
+ assertClusterEquals(expected, actual, expected.getName());
+ }
+
+ private void updateCluster(Cluster cluster) throws Exception {
+ Cluster updatedCluster =
+ instanceAdmin
+ .updateCluster(
+ Cluster.ofUpdateCluster(cluster).updateNumNodes(cluster.getServerNodes() + 1))
+ .get();
+ assertEquals(cluster.getServerNodes() + 1, updatedCluster.getServerNodes());
+ }
+
+ private void deleteCluster(Cluster cluster) {
+ instanceAdmin.deleteCluster(cluster.getName());
+ }
+
+ private void listInstances(int expectedSize) {
+ List instances = instanceAdmin.listInstances(TEST_PROJECT);
+ assertEquals(expectedSize, instances.size());
+
+ for (Instance instance : instances) {
+ getInstance(instance);
+ }
+ }
+
+ private void listClusters(InstanceName instanceName, int expectedSize) {
+ List clusters = instanceAdmin.listClusters(instanceName);
+ assertEquals(expectedSize, clusters.size());
+
+ for (Cluster cluster : clusters) {
+ getCluster(cluster);
+ }
+ }
+
+ private AppProfile createAppProfile(InstanceName instanceName, AppProfile rawProfile) {
+ AppProfile actual = instanceAdmin.createAppProfile(instanceName, rawProfile);
+ assertAppProfileEquals(
+ rawProfile,
+ actual,
+ AppProfileName.of(TEST_PROJECT.getProject(), TEST_PROD_INST_ID, rawProfile.getId()));
+ return actual;
+ }
+
+ private void getAppProfile(AppProfile expected) {
+ AppProfile actual = instanceAdmin.getAppProfile(expected.getName());
+ assertAppProfileEquals(expected, actual, expected.getName());
+ }
+
+ private void listAppProfiles(InstanceName instanceName, int expectedSize) {
+ List appProfiles = instanceAdmin.listAppProfiles(instanceName);
+ assertEquals(expectedSize, appProfiles.size());
+
+ for (AppProfile appProfile : appProfiles) {
+ getAppProfile(appProfile);
+ }
+ }
+
+ private void updateAppProfileToSingle(AppProfile original, String singleClusterId)
+ throws Exception {
+ AppProfile updated =
+ instanceAdmin
+ .updateAppProfile(
+ AppProfile.ofUpdateAppProfile(original)
+ .updateDescription("newDescription")
+ .updateRouteToCluster(singleClusterId, false))
+ .get();
+
+ assertEquals("newDescription", updated.getDescription());
+ assertEquals(RoutingPolicyCase.SINGLE_CLUSTER_ROUTING, updated.getRoutingPolicy().name());
+ }
+
+ private void deleteAppProfile(AppProfileName appProfileName) {
+ instanceAdmin.deleteAppProfile(appProfileName, true);
+
+ Exception ensureDelete = null;
+ try {
+ instanceAdmin.getAppProfile(appProfileName);
+ } catch (Exception e) {
+ ensureDelete = e;
+ }
+ assertNotNull(ensureDelete);
+ }
+
+ private static void assertInstanceEquals(Instance exptected, Instance actual) {
+ assertEquals(InstanceName.of(TEST_PROJECT.getProject(), exptected.getid()), actual.getName());
+ assertEquals(State.READY, actual.getState());
+
+ assertEquals(actual.getDisplayName(), actual.getDisplayName());
+ assertEquals(actual.getType(), actual.getType());
+ assertEquals(actual.getLabelsMap(), actual.getLabelsMap());
+ }
+
+ private void assertClusterEquals(Cluster exptected, Cluster actual, ClusterName expectedName) {
+ assertEquals(com.google.bigtable.admin.v2.Cluster.State.READY, actual.getState());
+ assertEquals(expectedName, actual.getName());
+ assertEquals(exptected.getId(), actual.getId());
+
+ assertEquals(exptected.getLocation(), actual.getLocation());
+ assertEquals(exptected.getServerNodes(), actual.getServerNodes());
+ assertEquals(StorageType.SSD, actual.getDefaultStorageType());
+ }
+
+ private void assertAppProfileEquals(
+ AppProfile exptected, AppProfile actual, AppProfileName expectedName) {
+ assertEquals(expectedName, actual.getName());
+
+ assertEquals(exptected.getId(), actual.getId());
+ assertEquals(exptected.getEtag(), actual.getEtag());
+ assertEquals(exptected.getDescription(), actual.getDescription());
+ assertEquals(exptected.getRoutingPolicy().toString(), actual.getRoutingPolicy().toString());
+ }
+}