Skip to content

Commit

Permalink
feat: Add admin APIs for AuthorizedView (#2175)
Browse files Browse the repository at this point in the history
* feat: Add admin APIs for AuthorizedView

Change-Id: Ie31eae6da61ed0d0462e029f6247924785b239bf

* chore: Mark AuthorizedViewType as InternalApi

Change-Id: If52e3a32c3259f652f1f7d34b013d1ec1fc0a773

* chore: Add tests and change AuthorizedViewType to InternalExtensionOnly

Change-Id: I2e7f04d0f7815d014928a924d4a4f26adb2b655d

* 🦉 Updates from OwlBot post-processor

See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md

* Chore: fix a comment

Change-Id: Iac28b6cbef3088e4e2d43d90655155369361c347

* setFamilySubset instead of add and use List rather than ImmutableList

Change-Id: Ibdb2c8a62dc55c44059d5ec2296c57c7d430baa4

---------

Co-authored-by: Lixia Chen <lixiachen@google.com>
Co-authored-by: Owl Bot <gcf-owl-bot[bot]@users.noreply.github.com>
  • Loading branch information
3 people committed Mar 27, 2024
1 parent 4158094 commit 13d1df3
Show file tree
Hide file tree
Showing 15 changed files with 2,442 additions and 0 deletions.

Large diffs are not rendered by default.

Expand Up @@ -34,6 +34,9 @@ public class NameUtil {
private static final Pattern BACKUP_PATTERN =
Pattern.compile("projects/([^/]+)/instances/([^/]+)/clusters/([^/]+)/backups/([^/]+)");

private static final Pattern AUTHORIZED_VIEW_PATTERN =
Pattern.compile("projects/([^/]+)/instances/([^/]+)/tables/([^/]+)/authorizedViews/([^/]+)");

public static String formatProjectName(String projectId) {
return "projects/" + projectId;
}
Expand All @@ -55,6 +58,11 @@ public static String formatBackupName(
return formatClusterName(projectId, instanceId, clusterId) + "/backups/" + backupId;
}

public static String formatAuthorizedViewName(
String projectId, String instanceId, String tableId, String viewId) {
return formatTableName(projectId, instanceId, tableId) + "/authorizedViews/" + viewId;
}

public static String extractTableIdFromTableName(String fullTableName) {
Matcher matcher = TABLE_PATTERN.matcher(fullTableName);
if (!matcher.matches()) {
Expand All @@ -71,6 +79,15 @@ public static String extractBackupIdFromBackupName(String fullBackupName) {
return matcher.group(4);
}

public static String extractAuthorizedViewIdFromAuthorizedViewName(
String fullAuthorizedViewName) {
Matcher matcher = AUTHORIZED_VIEW_PATTERN.matcher(fullAuthorizedViewName);
if (!matcher.matches()) {
throw new IllegalArgumentException("Invalid authorized view name: " + fullAuthorizedViewName);
}
return matcher.group(4);
}

public static String extractZoneIdFromLocationName(String fullLocationName) {
Matcher matcher = LOCATION_PATTERN.matcher(fullLocationName);
if (!matcher.matches()) {
Expand Down
@@ -0,0 +1,124 @@
/*
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.cloud.bigtable.admin.v2.models;

import com.google.api.core.InternalApi;
import com.google.api.core.InternalExtensionOnly;
import com.google.bigtable.admin.v2.AuthorizedViewName;
import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import javax.annotation.Nonnull;

/**
* A class that wraps the {@link com.google.bigtable.admin.v2.AuthorizedView} protocol buffer
* object.
*
* <p>An AuthorizedView represents subsets of a particular table based on rules. The access to each
* AuthorizedView can be configured separately from the Table.
*
* <p>Users can perform read/write operation on an AuthorizedView by providing an authorizedView id
* besides a table id, in which case the semantics remain identical as reading/writing on a Table
* except that visibility is restricted to the subset of the Table that the AuthorizedView
* represents.
*/
public final class AuthorizedView {
private final com.google.bigtable.admin.v2.AuthorizedView proto;

/**
* Wraps the protobuf. This method is considered an internal implementation detail and not meant
* to be used by applications.
*/
@InternalApi
public static AuthorizedView fromProto(
@Nonnull com.google.bigtable.admin.v2.AuthorizedView proto) {
return new AuthorizedView(proto);
}

private AuthorizedView(@Nonnull com.google.bigtable.admin.v2.AuthorizedView proto) {
Preconditions.checkNotNull(proto);
Preconditions.checkArgument(!proto.getName().isEmpty(), "AuthorizedView must have a name");
Preconditions.checkArgument(
proto.hasSubsetView(), "AuthorizedView must have a subset_view field");
this.proto = proto;
}

/** Gets the authorized view's id. */
public String getId() {
// Constructor ensures that name is not null.
AuthorizedViewName fullName = AuthorizedViewName.parse(proto.getName());

//noinspection ConstantConditions
return fullName.getAuthorizedView();
}

/** Gets the id of the table that owns this authorized view. */
public String getTableId() {
// Constructor ensures that name is not null.
AuthorizedViewName fullName = AuthorizedViewName.parse(proto.getName());

//noinspection ConstantConditions
return fullName.getTable();
}

/** Returns whether this authorized view is deletion protected. */
public boolean isDeletionProtected() {
return proto.getDeletionProtection();
}

/** Gets the type of this authorized view, which currently can only be a subset view. */
public AuthorizedViewType getAuthorizedViewType() {
if (proto.hasSubsetView()) {
return SubsetView.fromProto(proto.getSubsetView());
} else {
// Should never happen because the constructor verifies that one must exist.
throw new IllegalStateException("This AuthorizedView doesn't have a valid type specified");
}
}

/**
* Creates the request protobuf. This method is considered an internal implementation detail and
* not meant to be used by applications.
*/
@InternalApi
public com.google.bigtable.admin.v2.AuthorizedView toProto() {
return proto;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
AuthorizedView that = (AuthorizedView) o;
return Objects.equal(proto, that.proto);
}

@Override
public int hashCode() {
return Objects.hashCode(proto);
}

/**
* Represents a subset of a Table. Please check the implementations of this interface for more
* details.
*/
@InternalExtensionOnly
public interface AuthorizedViewType {}
}
@@ -0,0 +1,117 @@
/*
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.cloud.bigtable.admin.v2.models;

import com.google.api.core.InternalApi;
import com.google.cloud.bigtable.admin.v2.internal.NameUtil;
import com.google.cloud.bigtable.admin.v2.models.AuthorizedView.AuthorizedViewType;
import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import javax.annotation.Nonnull;

/**
* Parameters for creating a new Cloud Bigtable {@link AuthorizedView}, which represents subsets of
* a particular table.
*
* <p>Sample code:
*
* <pre>{@code
* CreateAuthorizedViewRequest request =
* CreateAuthorizedViewRequest.of("my-table", "my-new-authorized-view")
* .setAuthorizedViewType(
* SubsetView.create()
* .addRowPrefix("row#")
* .addFamilySubsets(
* "my-family", FamilySubsets.create().addQualifier("column")));
* }</pre>
*
* @see AuthorizedView for more details.
*/
public final class CreateAuthorizedViewRequest {
private final String tableId;
private final com.google.bigtable.admin.v2.CreateAuthorizedViewRequest.Builder requestBuilder =
com.google.bigtable.admin.v2.CreateAuthorizedViewRequest.newBuilder();

public static CreateAuthorizedViewRequest of(
@Nonnull String tableId, @Nonnull String authorizedViewId) {
return new CreateAuthorizedViewRequest(tableId, authorizedViewId);
}

private CreateAuthorizedViewRequest(@Nonnull String tableId, @Nonnull String authorizedViewId) {
Preconditions.checkNotNull(tableId, "tableId must be set");
Preconditions.checkNotNull(authorizedViewId, "authorizedViewId must be set");

this.tableId = tableId;
requestBuilder.setAuthorizedViewId(authorizedViewId);
}

/** Configures if the authorized view is deletion protected. */
public CreateAuthorizedViewRequest setDeletionProtection(boolean deletionProtection) {
requestBuilder.getAuthorizedViewBuilder().setDeletionProtection(deletionProtection);
return this;
}

/**
* Sets the implementation for this authorized view.
*
* @see AuthorizedViewType for details.
*/
public CreateAuthorizedViewRequest setAuthorizedViewType(
@Nonnull AuthorizedViewType authorizedViewType) {
Preconditions.checkNotNull(authorizedViewType, "authorizedViewType must be set");

if (authorizedViewType instanceof SubsetView) {
requestBuilder
.getAuthorizedViewBuilder()
.setSubsetView(((SubsetView) authorizedViewType).toProto());
} else {
throw new IllegalArgumentException("Unknown authorizedViewType: " + authorizedViewType);
}

return this;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
CreateAuthorizedViewRequest that = (CreateAuthorizedViewRequest) o;
return Objects.equal(requestBuilder.build(), that.requestBuilder.build())
&& Objects.equal(tableId, that.tableId);
}

@Override
public int hashCode() {
return Objects.hashCode(requestBuilder.build(), tableId);
}

/**
* Creates the request protobuf. This method is considered an internal implementation detail and
* not meant to be used by applications.
*/
@InternalApi
public com.google.bigtable.admin.v2.CreateAuthorizedViewRequest toProto(
@Nonnull String projectId, @Nonnull String instanceId) {
return requestBuilder
.setParent(NameUtil.formatTableName(projectId, instanceId, tableId))
.build();
}
}

0 comments on commit 13d1df3

Please sign in to comment.