Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: app profile multi cluster routing support with specified cluster ids #961

Merged
merged 4 commits into from Oct 20, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -22,6 +22,8 @@
import com.google.common.base.Preconditions;
import com.google.common.base.Verify;
import com.google.common.base.VerifyException;
import com.google.common.collect.ImmutableSet;
import java.util.Set;
import javax.annotation.Nonnull;

/**
Expand Down Expand Up @@ -64,7 +66,8 @@ private AppProfile(@Nonnull com.google.bigtable.admin.v2.AppProfile proto) {
@SuppressWarnings("WeakerAccess")
public RoutingPolicy getPolicy() {
if (proto.hasMultiClusterRoutingUseAny()) {
return MultiClusterRoutingPolicy.of();
return MultiClusterRoutingPolicy.of(
ImmutableSet.copyOf(proto.getMultiClusterRoutingUseAny().getClusterIdsList()));
} else if (proto.hasSingleClusterRouting()) {
return new SingleClusterRoutingPolicy(proto.getSingleClusterRouting());
} else {
Expand Down Expand Up @@ -226,15 +229,42 @@ public int hashCode() {
* available cluster.
*/
public static class MultiClusterRoutingPolicy implements RoutingPolicy {
private static final MultiClusterRoutingUseAny proto =
MultiClusterRoutingUseAny.getDefaultInstance();
private final MultiClusterRoutingUseAny proto;

/** Creates a new instance of {@link MultiClusterRoutingPolicy}. */
public static MultiClusterRoutingPolicy of() {
return new MultiClusterRoutingPolicy();
return new MultiClusterRoutingPolicy(MultiClusterRoutingUseAny.getDefaultInstance());
}

private MultiClusterRoutingPolicy() {}
/**
* Creates a new instance of {@link MultiClusterRoutingPolicy} with specified cluster ids to
* route to.
*/
public static MultiClusterRoutingPolicy of(String... clusterIds) {
return of(ImmutableSet.copyOf(clusterIds));
}

/**
* Creates a new instance of {@link MultiClusterRoutingPolicy} with specified cluster ids to
* route to.
*/
public static MultiClusterRoutingPolicy of(Set<String> clusterIds) {
return new MultiClusterRoutingPolicy(
MultiClusterRoutingUseAny.newBuilder().addAllClusterIds(clusterIds).build());
}

/*
* Returns the set of clusters to route to. The order is ignored; clusters will be
* tried in order of distance. If empty, all clusters are eligible.
*/
public Set<String> getClusterIds() {
return ImmutableSet.copyOf(proto.getClusterIdsList());
}

private MultiClusterRoutingPolicy(
com.google.bigtable.admin.v2.AppProfile.MultiClusterRoutingUseAny proto) {
this.proto = proto;
}

/**
* Creates the request protobuf. This method is considered an internal implementation detail and
Expand All @@ -253,8 +283,8 @@ public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) {
return false;
}

return true;
MultiClusterRoutingPolicy that = (MultiClusterRoutingPolicy) o;
return Objects.equal(proto, that.proto);
}

@Override
Expand Down
Expand Up @@ -50,6 +50,7 @@
import com.google.cloud.bigtable.admin.v2.models.UpdateAppProfileRequest;
import com.google.cloud.bigtable.admin.v2.models.UpdateInstanceRequest;
import com.google.cloud.bigtable.admin.v2.stub.BigtableInstanceAdminStub;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.io.BaseEncoding;
import com.google.protobuf.ByteString;
Expand Down Expand Up @@ -617,6 +618,131 @@ public void testCreateAppProfile() {
assertThat(actualResult).isEqualTo(AppProfile.fromProto(expectedResponse));
}

@Test
public void testCreateAppProfileAddSingleClusterId() {
// Setup
Mockito.when(mockStub.createAppProfileCallable()).thenReturn(mockCreateAppProfileCallable);

com.google.bigtable.admin.v2.CreateAppProfileRequest expectedRequest =
com.google.bigtable.admin.v2.CreateAppProfileRequest.newBuilder()
.setParent(NameUtil.formatInstanceName(PROJECT_ID, INSTANCE_ID))
.setAppProfileId(APP_PROFILE_ID)
.setAppProfile(
com.google.bigtable.admin.v2.AppProfile.newBuilder()
.setDescription("my description")
.setMultiClusterRoutingUseAny(
com.google.bigtable.admin.v2.AppProfile.MultiClusterRoutingUseAny
.newBuilder()
.addClusterIds("cluster-id-1")))
.build();

com.google.bigtable.admin.v2.AppProfile expectedResponse =
com.google.bigtable.admin.v2.AppProfile.newBuilder()
.setName(APP_PROFILE_NAME)
.setDescription("my description")
.setMultiClusterRoutingUseAny(
com.google.bigtable.admin.v2.AppProfile.MultiClusterRoutingUseAny.newBuilder()
.addClusterIds("cluster-id-1"))
.build();

Mockito.when(mockCreateAppProfileCallable.futureCall(expectedRequest))
.thenReturn(ApiFutures.immediateFuture(expectedResponse));

// Execute
AppProfile actualResult =
adminClient.createAppProfile(
CreateAppProfileRequest.of(INSTANCE_ID, APP_PROFILE_ID)
.setDescription("my description")
.setRoutingPolicy(MultiClusterRoutingPolicy.of("cluster-id-1")));

// Verify
assertThat(actualResult).isEqualTo(AppProfile.fromProto(expectedResponse));
}

@Test
public void testCreateAppProfileAddMultipleClusterIds() {
// Setup
Mockito.when(mockStub.createAppProfileCallable()).thenReturn(mockCreateAppProfileCallable);

com.google.bigtable.admin.v2.CreateAppProfileRequest expectedRequest =
com.google.bigtable.admin.v2.CreateAppProfileRequest.newBuilder()
.setParent(NameUtil.formatInstanceName(PROJECT_ID, INSTANCE_ID))
.setAppProfileId(APP_PROFILE_ID)
.setAppProfile(
com.google.bigtable.admin.v2.AppProfile.newBuilder()
.setDescription("my description")
.setMultiClusterRoutingUseAny(
com.google.bigtable.admin.v2.AppProfile.MultiClusterRoutingUseAny
.newBuilder()
.addClusterIds("cluster-id-1")
.addClusterIds("cluster-id-2")))
.build();

com.google.bigtable.admin.v2.AppProfile expectedResponse =
com.google.bigtable.admin.v2.AppProfile.newBuilder()
.setName(APP_PROFILE_NAME)
.setDescription("my description")
.setMultiClusterRoutingUseAny(
com.google.bigtable.admin.v2.AppProfile.MultiClusterRoutingUseAny.newBuilder()
.addClusterIds("cluster-id-1")
.addClusterIds("cluster-id-2"))
.build();

Mockito.when(mockCreateAppProfileCallable.futureCall(expectedRequest))
.thenReturn(ApiFutures.immediateFuture(expectedResponse));

// Execute
AppProfile actualResult =
adminClient.createAppProfile(
CreateAppProfileRequest.of(INSTANCE_ID, APP_PROFILE_ID)
.setDescription("my description")
.setRoutingPolicy(MultiClusterRoutingPolicy.of("cluster-id-1", "cluster-id-2")));

// Verify
assertThat(actualResult).isEqualTo(AppProfile.fromProto(expectedResponse));
}

@Test
public void testCreateAppProfileAddMultipleClusterIdsWithList() {
// Setup
Mockito.when(mockStub.createAppProfileCallable()).thenReturn(mockCreateAppProfileCallable);

com.google.bigtable.admin.v2.CreateAppProfileRequest expectedRequest =
com.google.bigtable.admin.v2.CreateAppProfileRequest.newBuilder()
.setParent(NameUtil.formatInstanceName(PROJECT_ID, INSTANCE_ID))
.setAppProfileId(APP_PROFILE_ID)
.setAppProfile(
com.google.bigtable.admin.v2.AppProfile.newBuilder()
.setDescription("my description")
.setMultiClusterRoutingUseAny(
com.google.bigtable.admin.v2.AppProfile.MultiClusterRoutingUseAny
.newBuilder()
.addAllClusterIds(ImmutableList.of("cluster-id-1", "cluster-id-2"))))
.build();

com.google.bigtable.admin.v2.AppProfile expectedResponse =
com.google.bigtable.admin.v2.AppProfile.newBuilder()
.setName(APP_PROFILE_NAME)
.setDescription("my description")
.setMultiClusterRoutingUseAny(
com.google.bigtable.admin.v2.AppProfile.MultiClusterRoutingUseAny.newBuilder()
.addAllClusterIds(ImmutableList.of("cluster-id-1", "cluster-id-2")))
.build();

Mockito.when(mockCreateAppProfileCallable.futureCall(expectedRequest))
.thenReturn(ApiFutures.immediateFuture(expectedResponse));

// Execute
AppProfile actualResult =
adminClient.createAppProfile(
CreateAppProfileRequest.of(INSTANCE_ID, APP_PROFILE_ID)
.setDescription("my description")
.setRoutingPolicy(MultiClusterRoutingPolicy.of("cluster-id-1", "cluster-id-2")));

// Verify
assertThat(actualResult).isEqualTo(AppProfile.fromProto(expectedResponse));
}

@Test
public void testGetAppProfile() {
// Setup
Expand Down
Expand Up @@ -96,6 +96,99 @@ public void appProfileTest() {
assertThat(actualEx).isNull();
}

@Test
public void appProfileTestMultiClusterWithIds() {
String newInstanceId = prefixGenerator.newPrefix();
String newClusterId = newInstanceId + "-c1";
String newClusterId2 = newInstanceId + "-c2";

client.createInstance(
CreateInstanceRequest.of(newInstanceId)
.addCluster(newClusterId, testEnvRule.env().getPrimaryZone(), 1, StorageType.SSD)
.addCluster(newClusterId2, testEnvRule.env().getSecondaryZone(), 1, StorageType.SSD)
.setDisplayName("Multi-Cluster-Instance-Test")
.addLabel("state", "readytodelete")
.setType(Type.PRODUCTION));

try {
assertThat(client.exists(newInstanceId)).isTrue();

String testAppProfile = "test-app-profile";

CreateAppProfileRequest request =
CreateAppProfileRequest.of(newInstanceId, testAppProfile)
.setRoutingPolicy(AppProfile.MultiClusterRoutingPolicy.of(newClusterId))
.setDescription("This is to test app profile");

AppProfile newlyCreatedAppProfile = client.createAppProfile(request);

AppProfile updated =
client.updateAppProfile(
UpdateAppProfileRequest.of(newlyCreatedAppProfile).setDescription("new description"));

AppProfile freshAppProfile = client.getAppProfile(newInstanceId, testAppProfile);
assertThat(freshAppProfile.getDescription()).isEqualTo(updated.getDescription());

AppProfile.MultiClusterRoutingPolicy freshAppProfilePolicy =
(AppProfile.MultiClusterRoutingPolicy) freshAppProfile.getPolicy();
AppProfile.MultiClusterRoutingPolicy updatedAppProfilePolicy =
(AppProfile.MultiClusterRoutingPolicy) updated.getPolicy();

assertThat(freshAppProfilePolicy.getClusterIds()).containsExactly(newClusterId);
assertThat(freshAppProfilePolicy.getClusterIds())
.isEqualTo(updatedAppProfilePolicy.getClusterIds());
assertThat(freshAppProfilePolicy).isEqualTo(updatedAppProfilePolicy);

assertThat(client.listAppProfiles(newInstanceId)).contains(freshAppProfile);

// update again with routing policy
AppProfile updated2 =
client.updateAppProfile(
UpdateAppProfileRequest.of(updated)
.setRoutingPolicy(AppProfile.MultiClusterRoutingPolicy.of(newClusterId2)));

AppProfile freshAppProfile2 = client.getAppProfile(newInstanceId, testAppProfile);
assertThat(freshAppProfile2.getDescription()).isEqualTo(updated2.getDescription());

AppProfile.MultiClusterRoutingPolicy freshAppProfilePolicy2 =
(AppProfile.MultiClusterRoutingPolicy) freshAppProfile2.getPolicy();
AppProfile.MultiClusterRoutingPolicy updatedAppProfilePolicy2 =
(AppProfile.MultiClusterRoutingPolicy) updated2.getPolicy();

assertThat(freshAppProfilePolicy2.getClusterIds()).containsExactly(newClusterId2);
assertThat(freshAppProfilePolicy2.getClusterIds())
.isEqualTo(updatedAppProfilePolicy2.getClusterIds());
assertThat(freshAppProfilePolicy2).isEqualTo(updatedAppProfilePolicy2);

assertThat(client.listAppProfiles(newInstanceId)).contains(freshAppProfile2);

// update to single routing policy
AppProfile updated3 =
client.updateAppProfile(
UpdateAppProfileRequest.of(updated)
.setRoutingPolicy(AppProfile.SingleClusterRoutingPolicy.of(newClusterId)));

AppProfile freshAppProfile3 = client.getAppProfile(newInstanceId, testAppProfile);
assertThat(freshAppProfile3.getDescription()).isEqualTo(updated3.getDescription());

AppProfile.SingleClusterRoutingPolicy freshAppProfilePolicy3 =
(AppProfile.SingleClusterRoutingPolicy) freshAppProfile3.getPolicy();
AppProfile.SingleClusterRoutingPolicy updatedAppProfilePolicy3 =
(AppProfile.SingleClusterRoutingPolicy) updated3.getPolicy();

assertThat(freshAppProfilePolicy3.getClusterId()).isEqualTo(newClusterId);
assertThat(freshAppProfilePolicy3.getClusterId())
.isEqualTo(updatedAppProfilePolicy3.getClusterId());
assertThat(freshAppProfilePolicy3).isEqualTo(updatedAppProfilePolicy3);

assertThat(client.listAppProfiles(newInstanceId)).contains(freshAppProfile3);
} finally {
if (client.exists(newInstanceId)) {
client.deleteInstance(newInstanceId);
}
}
}

@Test
public void iamUpdateTest() {
Policy policy = client.getIamPolicy(instanceId);
Expand Down
Expand Up @@ -20,6 +20,7 @@
import com.google.bigtable.admin.v2.AppProfile.SingleClusterRouting;
import com.google.bigtable.admin.v2.AppProfileName;
import com.google.cloud.bigtable.admin.v2.models.AppProfile.SingleClusterRoutingPolicy;
import com.google.common.collect.ImmutableList;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
Expand Down Expand Up @@ -48,6 +49,46 @@ public void testFromProto() {
assertThat(profile.getPolicy()).isEqualTo(SingleClusterRoutingPolicy.of("my-cluster", true));
}

@Test
public void testFromProtoWithMultiCluster() {
AppProfile profile =
AppProfile.fromProto(
com.google.bigtable.admin.v2.AppProfile.newBuilder()
.setName(AppProfileName.of("my-project", "my-instance", "my-profile").toString())
.setDescription("my description")
.setMultiClusterRoutingUseAny(
com.google.bigtable.admin.v2.AppProfile.MultiClusterRoutingUseAny.newBuilder()
.build())
.setEtag("my-etag")
.build());

assertThat(profile.getInstanceId()).isEqualTo("my-instance");
assertThat(profile.getId()).isEqualTo("my-profile");
assertThat(profile.getDescription()).isEqualTo("my description");
assertThat(profile.getPolicy()).isEqualTo(AppProfile.MultiClusterRoutingPolicy.of());
}

@Test
public void testFromProtoWithMultiClusterWithIds() {
AppProfile profile =
AppProfile.fromProto(
com.google.bigtable.admin.v2.AppProfile.newBuilder()
.setName(AppProfileName.of("my-project", "my-instance", "my-profile").toString())
.setDescription("my description")
.setMultiClusterRoutingUseAny(
com.google.bigtable.admin.v2.AppProfile.MultiClusterRoutingUseAny.newBuilder()
.addAllClusterIds(ImmutableList.of("cluster-id-1", "cluster-id-2"))
.build())
.setEtag("my-etag")
.build());

assertThat(profile.getInstanceId()).isEqualTo("my-instance");
assertThat(profile.getId()).isEqualTo("my-profile");
assertThat(profile.getDescription()).isEqualTo("my description");
assertThat(profile.getPolicy())
.isEqualTo(AppProfile.MultiClusterRoutingPolicy.of("cluster-id-1", "cluster-id-2"));
}

@Test
public void testNoNameError() {
Exception actualException = null;
Expand Down