Skip to content

Commit 18a11e8

Browse files
feat: add Dataset ACL support (#1763)
* feat: add Dataset ACL support * some lint updates * add back interface that was causing IDE issues * fix recursive import issue * debug * update code based on pending discovery doc changes (cl/421673680) * update code to reflect more changes (target_types should be List<String>) based on pending discovery doc changes (cl/421673680) * 🦉 Updates from OwlBot See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * rename to address feedback Co-authored-by: Owl Bot <gcf-owl-bot[bot]@users.noreply.github.com>
1 parent 0fe0a78 commit 18a11e8

File tree

4 files changed

+144
-10
lines changed

4 files changed

+144
-10
lines changed

google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/Acl.java

+81-8
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,11 @@
2020

2121
import com.google.api.core.ApiFunction;
2222
import com.google.api.services.bigquery.model.Dataset.Access;
23+
import com.google.api.services.bigquery.model.DatasetAccessEntry;
2324
import com.google.cloud.StringEnumType;
2425
import com.google.cloud.StringEnumValue;
2526
import java.io.Serializable;
27+
import java.util.List;
2628
import java.util.Objects;
2729

2830
/**
@@ -105,7 +107,8 @@ public enum Type {
105107
USER,
106108
VIEW,
107109
IAM_MEMBER,
108-
ROUTINE
110+
ROUTINE,
111+
DATASET
109112
}
110113

111114
Entity(Type type) {
@@ -119,6 +122,11 @@ public Type getType() {
119122
abstract Access toPb();
120123

121124
static Entity fromPb(Access access) {
125+
if (access.getDataset() != null) {
126+
return new DatasetAclEntity(
127+
DatasetId.fromPb(access.getDataset().getDataset()),
128+
access.getDataset().getTargetTypes());
129+
}
122130
if (access.getDomain() != null) {
123131
return new Domain(access.getDomain());
124132
}
@@ -146,6 +154,65 @@ static Entity fromPb(Access access) {
146154
}
147155
}
148156

157+
/**
158+
* Class for a BigQuery DatasetAclEntity ACL entity. Objects of this class represent a
159+
* DatasetAclEntity from a different DatasetAclEntity to grant access to. Only views are supported
160+
* for now. The role field is not required when this field is set. If that DatasetAclEntity is
161+
* deleted and re-created, its access needs to be granted again via an update operation.
162+
*/
163+
public static final class DatasetAclEntity extends Entity {
164+
165+
private static final long serialVersionUID = -8392885851733136526L;
166+
167+
private final DatasetId id;
168+
private final List<String> targetTypes;
169+
170+
/** Creates a DatasetAclEntity given the DatasetAclEntity's id. */
171+
public DatasetAclEntity(DatasetId id, List<String> targetTypes) {
172+
super(Type.DATASET);
173+
this.id = id;
174+
this.targetTypes = targetTypes;
175+
}
176+
177+
/** Returns DatasetAclEntity's identity. */
178+
public DatasetId getId() {
179+
return id;
180+
}
181+
182+
public List<String> getTargetTypes() {
183+
return targetTypes;
184+
}
185+
186+
@Override
187+
public boolean equals(Object obj) {
188+
if (this == obj) {
189+
return true;
190+
}
191+
if (obj == null || getClass() != obj.getClass()) {
192+
return false;
193+
}
194+
DatasetAclEntity datasetAclEntity = (DatasetAclEntity) obj;
195+
return Objects.equals(getType(), datasetAclEntity.getType())
196+
&& Objects.equals(id, datasetAclEntity.id);
197+
}
198+
199+
@Override
200+
public int hashCode() {
201+
return Objects.hash(getType(), id);
202+
}
203+
204+
@Override
205+
public String toString() {
206+
return toPb().toString();
207+
}
208+
209+
@Override
210+
Access toPb() {
211+
return new Access()
212+
.setDataset(new DatasetAccessEntry().setDataset(id.toPb()).setTargetTypes(targetTypes));
213+
}
214+
}
215+
149216
/**
150217
* Class for a BigQuery Domain entity. Objects of this class represent a domain to grant access
151218
* to. Any users signed in with the domain specified will be granted the specified access.
@@ -342,9 +409,10 @@ Access toPb() {
342409

343410
/**
344411
* Class for a BigQuery View entity. Objects of this class represent a view from a different
345-
* dataset to grant access to. Queries executed against that view will have read access to tables
346-
* in this dataset. The role field is not required when this field is set. If that view is updated
347-
* by any user, access to the view needs to be granted again via an update operation.
412+
* datasetAclEntity to grant access to. Queries executed against that view will have read access
413+
* to tables in this datasetAclEntity. The role field is not required when this field is set. If
414+
* that view is updated by any user, access to the view needs to be granted again via an update
415+
* operation.
348416
*/
349417
public static final class View extends Entity {
350418

@@ -393,10 +461,10 @@ Access toPb() {
393461

394462
/**
395463
* Class for a BigQuery Routine entity. Objects of this class represent a routine from a different
396-
* dataset to grant access to. Queries executed against that routine will have read access to
397-
* views/tables/routines in this dataset. Only UDF is supported for now. The role field is not
398-
* required when this field is set. If that routine is updated by any user, access to the routine
399-
* needs to be granted again via an update operation.
464+
* datasetAclEntity to grant access to. Queries executed against that routine will have read
465+
* access to views/tables/routines in this datasetAclEntity. Only UDF is supported for now. The
466+
* role field is not required when this field is set. If that routine is updated by any user,
467+
* access to the routine needs to be granted again via an update operation.
400468
*/
401469
public static final class Routine extends Entity {
402470

@@ -516,6 +584,11 @@ public static Acl of(Entity entity, Role role) {
516584
return new Acl(entity, role);
517585
}
518586

587+
/** Returns an Acl object for a datasetAclEntity. */
588+
public static Acl of(DatasetAclEntity datasetAclEntity) {
589+
return new Acl(datasetAclEntity, null);
590+
}
591+
519592
/** Returns an Acl object for a view entity. */
520593
public static Acl of(View view) {
521594
return new Acl(view, null);

google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/AclTest.java

+14
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import static org.junit.Assert.assertEquals;
2020

2121
import com.google.api.services.bigquery.model.Dataset;
22+
import com.google.cloud.bigquery.Acl.DatasetAclEntity;
2223
import com.google.cloud.bigquery.Acl.Domain;
2324
import com.google.cloud.bigquery.Acl.Entity;
2425
import com.google.cloud.bigquery.Acl.Entity.Type;
@@ -27,10 +28,23 @@
2728
import com.google.cloud.bigquery.Acl.Role;
2829
import com.google.cloud.bigquery.Acl.User;
2930
import com.google.cloud.bigquery.Acl.View;
31+
import com.google.common.collect.ImmutableList;
32+
import java.util.List;
3033
import org.junit.Test;
3134

3235
public class AclTest {
3336

37+
@Test
38+
public void testDatasetEntity() {
39+
DatasetId datasetId = DatasetId.of("dataset");
40+
List<String> targetTypes = ImmutableList.of("VIEWS");
41+
DatasetAclEntity entity = new DatasetAclEntity(datasetId, targetTypes);
42+
assertEquals(datasetId, entity.getId());
43+
assertEquals(targetTypes, entity.getTargetTypes());
44+
Dataset.Access pb = entity.toPb();
45+
assertEquals(entity, Entity.fromPb(pb));
46+
}
47+
3448
@Test
3549
public void testDomainEntity() {
3650
Domain entity = new Domain("d1");

google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/SerializationTest.java

+7-2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import com.google.cloud.NoCredentials;
2121
import com.google.cloud.PageImpl;
2222
import com.google.cloud.Restorable;
23+
import com.google.cloud.bigquery.Acl.DatasetAclEntity;
2324
import com.google.cloud.bigquery.StandardTableDefinition.StreamingBuffer;
2425
import com.google.common.collect.ImmutableList;
2526
import com.google.common.collect.ImmutableMap;
@@ -38,8 +39,6 @@ public class SerializationTest extends BaseSerializationTest {
3839
Acl.of(new Acl.View(TableId.of("project", "dataset", "table")), Acl.Role.WRITER);
3940
private static final Acl ROUTINE_ACCESS =
4041
Acl.of(new Acl.Routine(RoutineId.of("project", "dataset", "routine")), Acl.Role.WRITER);
41-
private static final List<Acl> ACCESS_RULES =
42-
ImmutableList.of(DOMAIN_ACCESS, GROUP_ACCESS, VIEW_ACCESS, ROUTINE_ACCESS, USER_ACCESS);
4342
private static final Long CREATION_TIME = System.currentTimeMillis() - 10;
4443
private static final Long DEFAULT_TABLE_EXPIRATION = 100L;
4544
private static final String DESCRIPTION = "Description";
@@ -50,6 +49,11 @@ public class SerializationTest extends BaseSerializationTest {
5049
private static final String LOCATION = "";
5150
private static final String SELF_LINK = "http://bigquery/p/d";
5251
private static final DatasetId DATASET_ID = DatasetId.of("project", "dataset");
52+
private static final List<String> TARGET_TYPES = ImmutableList.of("VIEWS");
53+
private static final Acl DATASET_ACCESS = Acl.of(new DatasetAclEntity(DATASET_ID, TARGET_TYPES));
54+
private static final List<Acl> ACCESS_RULES =
55+
ImmutableList.of(
56+
DOMAIN_ACCESS, GROUP_ACCESS, VIEW_ACCESS, ROUTINE_ACCESS, USER_ACCESS, DATASET_ACCESS);
5357
private static final DatasetInfo DATASET_INFO =
5458
DatasetInfo.newBuilder(DATASET_ID)
5559
.setAcl(ACCESS_RULES)
@@ -228,6 +232,7 @@ protected Serializable[] serializableObjects() {
228232
USER_ACCESS,
229233
VIEW_ACCESS,
230234
ROUTINE_ACCESS,
235+
DATASET_ACCESS,
231236
DATASET_ID,
232237
DATASET_INFO,
233238
TABLE_ID,

google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java

+42
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import com.google.cloud.Role;
3939
import com.google.cloud.ServiceOptions;
4040
import com.google.cloud.bigquery.Acl;
41+
import com.google.cloud.bigquery.Acl.DatasetAclEntity;
4142
import com.google.cloud.bigquery.BigQuery;
4243
import com.google.cloud.bigquery.BigQuery.DatasetDeleteOption;
4344
import com.google.cloud.bigquery.BigQuery.DatasetField;
@@ -1897,6 +1898,47 @@ public void testAuthorizeRoutine() {
18971898
assertEquals(routineAcl, routineDataset.getAcl());
18981899
}
18991900

1901+
@Test
1902+
public void testAuthorizeDataset() {
1903+
String datasetName = RemoteBigQueryHelper.generateDatasetName();
1904+
DatasetId datasetId = DatasetId.of(PROJECT_ID, datasetName);
1905+
List<String> targetTypes = ImmutableList.of("VIEWS");
1906+
// Specify the acl which will be shared to the authorized dataset
1907+
List<Acl> acl =
1908+
ImmutableList.of(
1909+
Acl.of(new Acl.Group("projectOwners"), Acl.Role.OWNER),
1910+
Acl.of(new Acl.IamMember("allUsers"), Acl.Role.READER));
1911+
DatasetInfo datasetInfo =
1912+
DatasetInfo.newBuilder(datasetId).setAcl(acl).setDescription("shared Dataset").build();
1913+
Dataset sharedDataset = bigquery.create(datasetInfo);
1914+
assertNotNull(sharedDataset);
1915+
assertEquals(sharedDataset.getDescription(), "shared Dataset");
1916+
// Get the current metadata for the dataset you want to share by calling the datasets.get method
1917+
List<Acl> sharedDatasetAcl = new ArrayList<>(sharedDataset.getAcl());
1918+
1919+
// Create a new dataset to be authorized
1920+
String authorizedDatasetName = RemoteBigQueryHelper.generateDatasetName();
1921+
DatasetId authorizedDatasetId = DatasetId.of(PROJECT_ID, authorizedDatasetName);
1922+
DatasetInfo authorizedDatasetInfo =
1923+
DatasetInfo.newBuilder(authorizedDatasetId)
1924+
.setDescription("new Dataset to be authorized by the sharedDataset")
1925+
.build();
1926+
Dataset authorizedDataset = bigquery.create(authorizedDatasetInfo);
1927+
assertNotNull(authorizedDataset);
1928+
assertEquals(
1929+
authorizedDataset.getDescription(), "new Dataset to be authorized by the sharedDataset");
1930+
1931+
// Add the new DatasetAccessEntry object to the existing sharedDatasetAcl list
1932+
DatasetAclEntity datasetEntity = new DatasetAclEntity(authorizedDatasetId, targetTypes);
1933+
sharedDatasetAcl.add(Acl.of(datasetEntity));
1934+
1935+
// Update the dataset with the added authorization
1936+
Dataset updatedDataset = sharedDataset.toBuilder().setAcl(sharedDatasetAcl).build().update();
1937+
1938+
// Verify that the authorized dataset has been added
1939+
assertEquals(sharedDatasetAcl, updatedDataset.getAcl());
1940+
}
1941+
19001942
@Test
19011943
public void testSingleStatementsQueryException() throws InterruptedException {
19021944
String invalidQuery =

0 commit comments

Comments
 (0)