Skip to content

Commit b031447

Browse files
author
Praful Makani
authored
feat: add acl for routine (#875)
1 parent ce6fd55 commit b031447

File tree

7 files changed

+121
-5
lines changed

7 files changed

+121
-5
lines changed

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

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,8 @@ public enum Type {
104104
GROUP,
105105
USER,
106106
VIEW,
107-
IAM_MEMBER
107+
IAM_MEMBER,
108+
ROUTINE
108109
}
109110

110111
Entity(Type type) {
@@ -136,6 +137,9 @@ static Entity fromPb(Access access) {
136137
if (access.getIamMember() != null) {
137138
return new IamMember(access.getIamMember());
138139
}
140+
if (access.getRoutine() != null) {
141+
return new Routine(RoutineId.fromPb(access.getRoutine()));
142+
}
139143
// Unreachable
140144
throw new BigQueryException(
141145
BigQueryException.UNKNOWN_CODE, "Unrecognized access configuration");
@@ -387,6 +391,58 @@ Access toPb() {
387391
}
388392
}
389393

394+
/**
395+
* 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.
400+
*/
401+
public static final class Routine extends Entity {
402+
403+
private static final long serialVersionUID = -8392885851733136262L;
404+
405+
private final RoutineId id;
406+
407+
/** Creates a Routine entity given the routine's id. */
408+
public Routine(RoutineId id) {
409+
super(Type.ROUTINE);
410+
this.id = id;
411+
}
412+
413+
/** Returns routine's identity. */
414+
public RoutineId getId() {
415+
return id;
416+
}
417+
418+
@Override
419+
public boolean equals(Object obj) {
420+
if (this == obj) {
421+
return true;
422+
}
423+
if (obj == null || getClass() != obj.getClass()) {
424+
return false;
425+
}
426+
Routine routine = (Routine) obj;
427+
return Objects.equals(getType(), routine.getType()) && Objects.equals(id, routine.id);
428+
}
429+
430+
@Override
431+
public int hashCode() {
432+
return Objects.hash(getType(), id);
433+
}
434+
435+
@Override
436+
public String toString() {
437+
return toPb().toString();
438+
}
439+
440+
@Override
441+
Access toPb() {
442+
return new Access().setRoutine(id.toPb());
443+
}
444+
}
445+
390446
/**
391447
* Class for a BigQuery IamMember entity. Objects of this class represent a iamMember to grant
392448
* access to given the IAM Policy.
@@ -465,6 +521,11 @@ public static Acl of(View view) {
465521
return new Acl(view, null);
466522
}
467523

524+
/** Returns an Acl object for a routine entity. */
525+
public static Acl of(Routine routine) {
526+
return new Acl(routine, null);
527+
}
528+
468529
@Override
469530
public int hashCode() {
470531
return Objects.hash(entity, role);

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
import com.google.api.client.util.Data;
2323
import com.google.api.services.bigquery.model.Dataset;
24+
import com.google.api.services.bigquery.model.RoutineReference;
2425
import com.google.api.services.bigquery.model.TableReference;
2526
import com.google.common.base.Function;
2627
import com.google.common.base.MoreObjects;
@@ -509,6 +510,13 @@ DatasetInfo setProjectId(String projectId) {
509510
viewReferencePb.setProjectId(projectId);
510511
}
511512
acls.add(Acl.of(new Acl.View(TableId.fromPb(viewReferencePb))));
513+
} else if (acl.getEntity().getType() == Acl.Entity.Type.ROUTINE) {
514+
Dataset.Access accessPb = acl.toPb();
515+
RoutineReference routineReferencePb = accessPb.getRoutine();
516+
if (routineReferencePb.getProjectId() == null) {
517+
routineReferencePb.setProjectId(projectId);
518+
}
519+
acls.add(Acl.of(new Acl.Routine(RoutineId.fromPb(routineReferencePb))));
512520
} else {
513521
acls.add(acl);
514522
}

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,16 @@ public void testViewEntity() {
8888
assertEquals(entity, Entity.fromPb(pb));
8989
}
9090

91+
@Test
92+
public void testRoutineEntity() {
93+
RoutineId routineId = RoutineId.of("project", "dataset", "routine");
94+
Acl.Routine entity = new Acl.Routine(routineId);
95+
assertEquals(routineId, entity.getId());
96+
assertEquals(Type.ROUTINE, entity.getType());
97+
Dataset.Access pb = entity.toPb();
98+
assertEquals(entity, Entity.fromPb(pb));
99+
}
100+
91101
@Test
92102
public void testIamMemberEntity() {
93103
IamMember entity = new IamMember("member1");
@@ -107,5 +117,9 @@ public void testOf() {
107117
acl = Acl.of(view);
108118
assertEquals(view, acl.getEntity());
109119
assertEquals(null, acl.getRole());
120+
Acl.Routine routine = new Acl.Routine(RoutineId.of("project", "dataset", "routine"));
121+
acl = Acl.of(routine);
122+
assertEquals(routine, acl.getEntity());
123+
assertEquals(null, acl.getRole());
110124
}
111125
}

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,13 @@ public class DatasetInfoTest {
3131
private static final List<Acl> ACCESS_RULES =
3232
ImmutableList.of(
3333
Acl.of(Acl.Group.ofAllAuthenticatedUsers(), Acl.Role.READER),
34-
Acl.of(new Acl.View(TableId.of("dataset", "table"))));
34+
Acl.of(new Acl.View(TableId.of("dataset", "table"))),
35+
Acl.of(new Acl.Routine(RoutineId.of("dataset", "routine"))));
3536
private static final List<Acl> ACCESS_RULES_COMPLETE =
3637
ImmutableList.of(
3738
Acl.of(Acl.Group.ofAllAuthenticatedUsers(), Acl.Role.READER),
38-
Acl.of(new Acl.View(TableId.of("project", "dataset", "table"))));
39+
Acl.of(new Acl.View(TableId.of("project", "dataset", "table"))),
40+
Acl.of(new Acl.Routine(RoutineId.of("project", "dataset", "routine"))));
3941
private static final List<Acl> ACCESS_RULES_IAM_MEMBER =
4042
ImmutableList.of(Acl.of(new Acl.IamMember("allUsers"), Acl.Role.READER));
4143
private static final Map<String, String> LABELS =

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ public class DatasetTest {
4949
private static final List<Acl> ACCESS_RULES =
5050
ImmutableList.of(
5151
Acl.of(Acl.Group.ofAllAuthenticatedUsers(), Acl.Role.READER),
52-
Acl.of(new Acl.View(TableId.of("dataset", "table"))));
52+
Acl.of(new Acl.View(TableId.of("dataset", "table"))),
53+
Acl.of(new Acl.Routine(RoutineId.of("dataset", "routine"))));
5354
private static final Map<String, String> LABELS =
5455
ImmutableMap.of(
5556
"example-label1", "example-value1",

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,10 @@ public class SerializationTest extends BaseSerializationTest {
3636
private static final Acl USER_ACCESS = Acl.of(new Acl.User("user"), Acl.Role.OWNER);
3737
private static final Acl VIEW_ACCESS =
3838
Acl.of(new Acl.View(TableId.of("project", "dataset", "table")), Acl.Role.WRITER);
39+
private static final Acl ROUTINE_ACCESS =
40+
Acl.of(new Acl.Routine(RoutineId.of("project", "dataset", "routine")), Acl.Role.WRITER);
3941
private static final List<Acl> ACCESS_RULES =
40-
ImmutableList.of(DOMAIN_ACCESS, GROUP_ACCESS, VIEW_ACCESS, USER_ACCESS);
42+
ImmutableList.of(DOMAIN_ACCESS, GROUP_ACCESS, VIEW_ACCESS, ROUTINE_ACCESS, USER_ACCESS);
4143
private static final Long CREATION_TIME = System.currentTimeMillis() - 10;
4244
private static final Long DEFAULT_TABLE_EXPIRATION = 100L;
4345
private static final String DESCRIPTION = "Description";
@@ -225,6 +227,7 @@ protected Serializable[] serializableObjects() {
225227
GROUP_ACCESS,
226228
USER_ACCESS,
227229
VIEW_ACCESS,
230+
ROUTINE_ACCESS,
228231
DATASET_ID,
229232
DATASET_INFO,
230233
TABLE_ID,

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

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@
112112
import java.nio.ByteBuffer;
113113
import java.nio.charset.StandardCharsets;
114114
import java.nio.file.FileSystems;
115+
import java.util.ArrayList;
115116
import java.util.Collection;
116117
import java.util.Collections;
117118
import java.util.HashMap;
@@ -1491,6 +1492,32 @@ public void testRoutineAPICreation() {
14911492
assertEquals(routine.getRoutineType(), "SCALAR_FUNCTION");
14921493
}
14931494

1495+
@Test
1496+
public void testAuthorizeRoutine() {
1497+
String routineName = RemoteBigQueryHelper.generateRoutineName();
1498+
RoutineId routineId = RoutineId.of(PROJECT_ID, ROUTINE_DATASET, routineName);
1499+
RoutineInfo routineInfo =
1500+
RoutineInfo.newBuilder(routineId)
1501+
.setRoutineType("SCALAR_FUNCTION")
1502+
.setBody("x * 3")
1503+
.setLanguage("SQL")
1504+
.setArguments(
1505+
ImmutableList.of(
1506+
RoutineArgument.newBuilder()
1507+
.setName("x")
1508+
.setDataType(StandardSQLDataType.newBuilder("INT64").build())
1509+
.build()))
1510+
.build();
1511+
Routine routine = bigquery.create(routineInfo);
1512+
assertNotNull(routine);
1513+
assertEquals(routine.getRoutineType(), "SCALAR_FUNCTION");
1514+
Dataset routineDataset = bigquery.getDataset(ROUTINE_DATASET);
1515+
List<Acl> routineAcl = new ArrayList<>(routineDataset.getAcl());
1516+
routineAcl.add(Acl.of(new Acl.Routine(routineId)));
1517+
routineDataset = routineDataset.toBuilder().setAcl(routineAcl).build().update();
1518+
assertEquals(routineAcl, routineDataset.getAcl());
1519+
}
1520+
14941521
@Test
14951522
public void testSingleStatementsQueryException() throws InterruptedException {
14961523
String invalidQuery =

0 commit comments

Comments
 (0)