Skip to content

Commit f3d3be2

Browse files
committed
Extend StorageExample to show how to add ACLs to blobs and buckets
1 parent 11f4573 commit f3d3be2

File tree

1 file changed

+244
-4
lines changed

1 file changed

+244
-4
lines changed

gcloud-java-examples/src/main/java/com/google/cloud/examples/storage/StorageExample.java

Lines changed: 244 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
import com.google.cloud.AuthCredentials.ServiceAccountAuthCredentials;
2121
import com.google.cloud.ReadChannel;
2222
import com.google.cloud.WriteChannel;
23+
import com.google.cloud.examples.compute.ComputeExample;
24+
import com.google.cloud.storage.Acl;
2325
import com.google.cloud.storage.Blob;
2426
import com.google.cloud.storage.BlobId;
2527
import com.google.cloud.storage.BlobInfo;
@@ -30,7 +32,9 @@
3032
import com.google.cloud.storage.Storage.CopyRequest;
3133
import com.google.cloud.storage.Storage.SignUrlOption;
3234
import com.google.cloud.storage.StorageOptions;
35+
import com.google.cloud.storage.spi.StorageRpc;
3336
import com.google.cloud.storage.spi.StorageRpc.Tuple;
37+
import com.google.common.collect.ImmutableMap;
3438

3539
import java.io.FileOutputStream;
3640
import java.io.IOException;
@@ -51,6 +55,7 @@
5155
import java.util.Arrays;
5256
import java.util.HashMap;
5357
import java.util.Iterator;
58+
import java.util.LinkedList;
5459
import java.util.List;
5560
import java.util.Map;
5661
import java.util.concurrent.TimeUnit;
@@ -75,7 +80,11 @@
7580
* cp <from_bucket> <from_path> <to_bucket> <to_path> |
7681
* compose <bucket> <from_path>+ <to_path> |
7782
* update_metadata <bucket> <file> [key=value]* |
78-
* sign_url <service_account_private_key_file> <service_account_email> <bucket> <path>"}</pre>
83+
* sign_url <service_account_private_key_file> <service_account_email> <bucket> <path> |
84+
* add-acl domain <bucket> <path>? <domain> OWNER|READER|WRITER |
85+
* add-acl project <bucket> <path>? <projectId>:(OWNERS|EDITORS|VIEWERS) OWNER|READER|WRITER |
86+
* add-acl user <bucket> <path>? <userEmail>|allUsers|allAuthenticatedUsers OWNER|READER|WRITER |
87+
* add-acl group <bucket> <path>? <group> OWNER|READER|WRITER"}</pre>
7988
* </li>
8089
* </ol>
8190
*
@@ -87,6 +96,7 @@
8796
public class StorageExample {
8897

8998
private static final Map<String, StorageAction> ACTIONS = new HashMap<>();
99+
private static final Map<String, StorageAction> ACL_ACTIONS = new HashMap<>();
90100

91101
private abstract static class StorageAction<T> {
92102

@@ -119,6 +129,48 @@ public String params() {
119129
}
120130
}
121131

132+
private static class ParentAction extends StorageAction<StorageRpc.Tuple<StorageAction, Object>> {
133+
134+
private final Map<String, StorageAction> subActions;
135+
136+
ParentAction(Map<String, StorageAction> subActions) {
137+
this.subActions = ImmutableMap.copyOf(subActions);
138+
}
139+
140+
@Override
141+
@SuppressWarnings("unchecked")
142+
void run(Storage storage, StorageRpc.Tuple<StorageAction, Object> subaction) throws Exception {
143+
subaction.x().run(storage, subaction.y());
144+
}
145+
146+
@Override
147+
StorageRpc.Tuple<StorageAction, Object> parse(String... args) throws Exception {
148+
if (args.length >= 1) {
149+
StorageAction action = subActions.get(args[0]);
150+
if (action != null) {
151+
Object actionArguments = action.parse(Arrays.copyOfRange(args, 1, args.length));
152+
return StorageRpc.Tuple.of(action, actionArguments);
153+
} else {
154+
throw new IllegalArgumentException("Unrecognized entity '" + args[0] + "'.");
155+
}
156+
}
157+
throw new IllegalArgumentException("Missing required entity.");
158+
}
159+
160+
@Override
161+
public String params() {
162+
StringBuilder builder = new StringBuilder();
163+
for (Map.Entry<String, StorageAction> entry : subActions.entrySet()) {
164+
builder.append('\n').append(entry.getKey());
165+
String param = entry.getValue().params();
166+
if (param != null && !param.isEmpty()) {
167+
builder.append(' ').append(param);
168+
}
169+
}
170+
return builder.toString();
171+
}
172+
}
173+
122174
/**
123175
* This class demonstrates how to retrieve Bucket or Blob metadata.
124176
* If more than one blob is supplied a Batch operation would be used to get all blobs metadata
@@ -512,6 +564,188 @@ public String params() {
512564
}
513565
}
514566

567+
private abstract static class AclAction extends StorageAction<Tuple<BlobId, Acl>> {
568+
569+
@Override
570+
public void run(Storage storage, Tuple<BlobId, Acl> params) {
571+
BlobId blobId = params.x();
572+
Acl acl = params.y();
573+
if (blobId.name().isEmpty()) {
574+
Bucket bucket = storage.get(blobId.bucket());
575+
if (bucket == null) {
576+
System.out.printf("Bucket %s does not exist%n", blobId.bucket());
577+
return;
578+
}
579+
bucket.toBuilder().acl(addAcl(bucket.acl(), acl)).build().update();
580+
System.out.printf("Added ACL %s to bucket %s%n", acl, blobId.bucket());
581+
} else {
582+
Blob blob = storage.get(blobId);
583+
if (blob == null) {
584+
System.out.printf("Blob %s does not exist%n", blobId);
585+
return;
586+
}
587+
blob.toBuilder().acl(addAcl(blob.acl(), acl)).build().update();
588+
System.out.printf("Added ACL %s to blob %s%n", acl, blobId);
589+
}
590+
}
591+
592+
private static List<Acl> addAcl(List<Acl> acls, Acl newAcl) {
593+
List<Acl> newAcls = new LinkedList<>(acls);
594+
newAcls.add(newAcl);
595+
return newAcls;
596+
}
597+
}
598+
599+
/**
600+
* This class demonstrates how to add an ACL to a blob or a bucket for a group of users
601+
* (identified by the group's email).
602+
*
603+
* @see <a href="https://cloud.google.com/storage/docs/access-control/lists#permissions">Access
604+
* Control Lists (ACLs)</a>
605+
*/
606+
private static class AddGroupAclAction extends AclAction {
607+
608+
@Override
609+
Tuple<BlobId, Acl> parse(String... args) {
610+
if (args.length >= 3) {
611+
BlobId blob;
612+
int nextArg;
613+
if (args.length == 3) {
614+
blob = BlobId.of(args[0], "");
615+
nextArg = 1;
616+
} else if (args.length == 4) {
617+
blob = BlobId.of(args[0], args[1]);
618+
nextArg = 2;
619+
} else {
620+
throw new IllegalArgumentException("Too many arguments.");
621+
}
622+
String group = args[nextArg++];
623+
Acl.Role role = Acl.Role.valueOf(args[nextArg]);
624+
return Tuple.of(blob, Acl.of(new Acl.Group(group), role));
625+
}
626+
throw new IllegalArgumentException("Missing required bucket, groupEmail or role arguments.");
627+
}
628+
629+
@Override
630+
public String params() {
631+
return "<bucket> <path>? <group> OWNER|READER|WRITER";
632+
}
633+
}
634+
635+
/**
636+
* This class demonstrates how to add an ACL to a blob or a bucket for a domain.
637+
*
638+
* @see <a href="https://cloud.google.com/storage/docs/access-control/lists#permissions">Access
639+
* Control Lists (ACLs)</a>
640+
*/
641+
private static class AddDomainAclAction extends AclAction {
642+
643+
@Override
644+
Tuple<BlobId, Acl> parse(String... args) {
645+
if (args.length >= 3) {
646+
BlobId blob;
647+
int nextArg;
648+
if (args.length == 3) {
649+
blob = BlobId.of(args[0], "");
650+
nextArg = 1;
651+
} else if (args.length == 4) {
652+
blob = BlobId.of(args[0], args[1]);
653+
nextArg = 2;
654+
} else {
655+
throw new IllegalArgumentException("Too many arguments.");
656+
}
657+
String domain = args[nextArg++];
658+
Acl.Role role = Acl.Role.valueOf(args[nextArg]);
659+
return Tuple.of(blob, Acl.of(new Acl.Domain(domain), role));
660+
}
661+
throw new IllegalArgumentException("Missing required bucket, domain or role arguments.");
662+
}
663+
664+
@Override
665+
public String params() {
666+
return "<bucket> <path>? <domain> OWNER|READER|WRITER";
667+
}
668+
}
669+
670+
/**
671+
* This class demonstrates how to add an ACL to a blob or a bucket for either a user (if an email
672+
* is provided), all users (if {@code allUsers} is provided), or all authenticated users (if
673+
* {@code allAuthenticatedUsers} is provided).
674+
*
675+
* @see <a href="https://cloud.google.com/storage/docs/access-control/lists#permissions">Access
676+
* Control Lists (ACLs)</a>
677+
*/
678+
private static class AddUserAclAction extends AclAction {
679+
680+
@Override
681+
Tuple<BlobId, Acl> parse(String... args) {
682+
if (args.length >= 3) {
683+
BlobId blob;
684+
int nextArg;
685+
if (args.length == 3) {
686+
blob = BlobId.of(args[0], "");
687+
nextArg = 1;
688+
} else if (args.length == 4) {
689+
blob = BlobId.of(args[0], args[1]);
690+
nextArg = 2;
691+
} else {
692+
throw new IllegalArgumentException("Too many arguments.");
693+
}
694+
String user = args[nextArg++];
695+
Acl.Role role = Acl.Role.valueOf(args[nextArg]);
696+
return Tuple.of(blob, Acl.of(new Acl.User(user), role));
697+
}
698+
throw new IllegalArgumentException("Missing required bucket, userEmail or role arguments.");
699+
}
700+
701+
@Override
702+
public String params() {
703+
return "<bucket> <path>? <userEmail>|allUsers|allAuthenticatedUsers OWNER|READER|WRITER";
704+
}
705+
}
706+
707+
/**
708+
* This class demonstrates how to add an ACL to a blob or a bucket for all users that have a
709+
* specific role in a provided project.
710+
*
711+
* @see <a href="https://cloud.google.com/storage/docs/access-control/lists#permissions">Access
712+
* Control Lists (ACLs)</a>
713+
*/
714+
private static class AddProjectAclAction extends AclAction {
715+
716+
@Override
717+
Tuple<BlobId, Acl> parse(String... args) {
718+
if (args.length >= 3) {
719+
BlobId blob;
720+
int nextArg;
721+
if (args.length == 3) {
722+
blob = BlobId.of(args[0], "");
723+
nextArg = 1;
724+
} else if (args.length == 4) {
725+
blob = BlobId.of(args[0], args[1]);
726+
nextArg = 2;
727+
} else {
728+
throw new IllegalArgumentException("Too many arguments.");
729+
}
730+
String[] projectAndRole = args[nextArg++].split(":");
731+
if (projectAndRole.length != 2) {
732+
throw new IllegalArgumentException(
733+
"Project entity must be specified as <projectId>:(OWNERS|READERS|WRITERS)");
734+
} else {
735+
Acl.Project.ProjectRole projectRole = Acl.Project.ProjectRole.valueOf(projectAndRole[1]);
736+
Acl.Role role = Acl.Role.valueOf(args[nextArg]);
737+
return Tuple.of(blob, Acl.of(new Acl.Project(projectRole, projectAndRole[0]), role));
738+
}
739+
}
740+
throw new IllegalArgumentException("Missing required bucket, project or role arguments.");
741+
}
742+
743+
@Override
744+
public String params() {
745+
return "<bucket> <path>? <projectId>:(OWNERS|EDITORS|VIEWERS) OWNER|READER|WRITER";
746+
}
747+
}
748+
515749
static {
516750
ACTIONS.put("info", new InfoAction());
517751
ACTIONS.put("delete", new DeleteAction());
@@ -522,6 +756,11 @@ public String params() {
522756
ACTIONS.put("compose", new ComposeAction());
523757
ACTIONS.put("update_metadata", new UpdateMetadataAction());
524758
ACTIONS.put("sign_url", new SignUrlAction());
759+
ACL_ACTIONS.put("group", new AddGroupAclAction());
760+
ACL_ACTIONS.put("domain", new AddDomainAclAction());
761+
ACL_ACTIONS.put("user", new AddUserAclAction());
762+
ACL_ACTIONS.put("project", new AddProjectAclAction());
763+
ACTIONS.put("add-acl", new ParentAction(ACL_ACTIONS));
525764
}
526765

527766
private static void printUsage() {
@@ -531,11 +770,12 @@ private static void printUsage() {
531770

532771
String param = entry.getValue().params();
533772
if (param != null && !param.isEmpty()) {
534-
actionAndParams.append(' ').append(param);
773+
// Add extra padding for multi-line action
774+
actionAndParams.append(' ').append(param.replace("\n", "\n\t\t"));
535775
}
536776
}
537-
System.out.printf("Usage: %s [<project_id>] operation <args>*%s%n",
538-
StorageExample.class.getSimpleName(), actionAndParams);
777+
System.out.printf("Usage: %s [<project_id>] operation [entity] <args>*%s%n",
778+
ComputeExample.class.getSimpleName(), actionAndParams);
539779
}
540780

541781
@SuppressWarnings("unchecked")

0 commit comments

Comments
 (0)