git-svn-id: https://s3tools.svn.sourceforge.net/svnroot/s3tools/s3cmd/trunk@332 830e0280-6d2a-0410-9c65-932aecc39d9d
Michal Ludvig authored on 2009/01/07 19:22:56... | ... |
@@ -1,5 +1,12 @@ |
1 | 1 |
2009-01-07 Michal Ludvig <michal@logix.cz> |
2 | 2 |
|
3 |
+ * s3cmd: New command 'setacl'. |
|
4 |
+ * S3/S3.py: Implemented set_acl(). |
|
5 |
+ * S3/ACL.py: Fill in <Owner/> tag in ACL XML. |
|
6 |
+ * NEWS: Info about 'setacl'. |
|
7 |
+ |
|
8 |
+2009-01-07 Michal Ludvig <michal@logix.cz> |
|
9 |
+ |
|
3 | 10 |
* s3cmd: Factored remote_keys generation from cmd_object_get() |
4 | 11 |
to fetch_remote_keys(). |
5 | 12 |
* s3cmd: Display Public URL in 'info' for AnonRead objects. |
... | ... |
@@ -51,18 +51,25 @@ class GranteeAnonRead(Grantee): |
51 | 51 |
permission = "READ" |
52 | 52 |
|
53 | 53 |
class ACL(object): |
54 |
- EMPTY_ACL = "<AccessControlPolicy><AccessControlList></AccessControlList></AccessControlPolicy>" |
|
54 |
+ EMPTY_ACL = "<AccessControlPolicy><Owner><ID></ID></Owner><AccessControlList></AccessControlList></AccessControlPolicy>" |
|
55 | 55 |
|
56 | 56 |
grantees = [] |
57 |
+ owner_id = "" |
|
58 |
+ owner_nick = "" |
|
57 | 59 |
|
58 | 60 |
def __init__(self, xml = None): |
59 | 61 |
if not xml: |
60 | 62 |
xml = ACL.EMPTY_ACL |
61 |
- self.tree = getTreeFromXml(xml) |
|
62 |
- self.parseGrants() |
|
63 |
- |
|
64 |
- def parseGrants(self): |
|
65 |
- for grant in self.tree.findall(".//Grant"): |
|
63 |
+ tree = getTreeFromXml(xml) |
|
64 |
+ self.parseOwner(tree) |
|
65 |
+ self.parseGrants(tree) |
|
66 |
+ |
|
67 |
+ def parseOwner(self, tree): |
|
68 |
+ self.owner_id = tree.findtext(".//Owner//ID") |
|
69 |
+ self.owner_nick = tree.findtext(".//Owner//DisplayName") |
|
70 |
+ |
|
71 |
+ def parseGrants(self, tree): |
|
72 |
+ for grant in tree.findall(".//Grant"): |
|
66 | 73 |
grantee = Grantee() |
67 | 74 |
g = grant.find(".//Grantee") |
68 | 75 |
grantee.xsi_type = g.attrib['{http://www.w3.org/2001/XMLSchema-instance}type'] |
... | ... |
@@ -87,6 +94,9 @@ class ACL(object): |
87 | 87 |
acl[user] = grantee.permission |
88 | 88 |
return acl |
89 | 89 |
|
90 |
+ def getOwner(self): |
|
91 |
+ return { 'id' : self.owner_id, 'nick' : self.owner_nick } |
|
92 |
+ |
|
90 | 93 |
def isAnonRead(self): |
91 | 94 |
for grantee in self.grantees: |
92 | 95 |
if grantee.isAnonRead(): |
... | ... |
@@ -103,6 +113,8 @@ class ACL(object): |
103 | 103 |
def __str__(self): |
104 | 104 |
tree = getTreeFromXml(ACL.EMPTY_ACL) |
105 | 105 |
tree.attrib['xmlns'] = "http://s3.amazonaws.com/doc/2006-03-01/" |
106 |
+ owner = tree.find(".//Owner//ID") |
|
107 |
+ owner.text = self.owner_id |
|
106 | 108 |
acl = tree.find(".//AccessControlList") |
107 | 109 |
for grantee in self.grantees: |
108 | 110 |
acl.append(grantee.getElement()) |
... | ... |
@@ -256,6 +256,17 @@ class S3(object): |
256 | 256 |
acl = ACL(response['data']) |
257 | 257 |
return acl |
258 | 258 |
|
259 |
+ def set_acl(self, uri, acl): |
|
260 |
+ if uri.has_object(): |
|
261 |
+ request = self.create_request("OBJECT_PUT", uri = uri, extra = "?acl") |
|
262 |
+ else: |
|
263 |
+ request = self.create_request("BUCKET_CREATE", bucket = uri.bucket(), extra = "?acl") |
|
264 |
+ |
|
265 |
+ body = str(acl) |
|
266 |
+ debug(u"set_acl(%s): acl-xml: %s" % (uri, body)) |
|
267 |
+ response = self.send_request(request, body) |
|
268 |
+ return response |
|
269 |
+ |
|
259 | 270 |
## Low level methods |
260 | 271 |
def urlencode_string(self, string): |
261 | 272 |
if type(string) == unicode: |
... | ... |
@@ -884,7 +884,34 @@ def cmd_sync(args): |
884 | 884 |
return cmd_sync_local2remote(src, dst) |
885 | 885 |
if S3Uri(src).type == "s3" and S3Uri(dst).type == "file": |
886 | 886 |
return cmd_sync_remote2local(src, dst) |
887 |
- |
|
887 |
+ |
|
888 |
+def cmd_setacl(args): |
|
889 |
+ s3 = S3(cfg) |
|
890 |
+ |
|
891 |
+ set_to_acl = cfg.acl_public and "Public" or "Private" |
|
892 |
+ |
|
893 |
+ remote_keys = fetch_remote_keys(args) |
|
894 |
+ total_keys = len(remote_keys) |
|
895 |
+ seq = 0 |
|
896 |
+ for key in remote_keys: |
|
897 |
+ seq += 1 |
|
898 |
+ seq_label = "[%d of %d]" % (seq, total_keys) |
|
899 |
+ uri = key['remote_uri'] |
|
900 |
+ acl = s3.get_acl(uri) |
|
901 |
+ if cfg.acl_public: |
|
902 |
+ if acl.isAnonRead(): |
|
903 |
+ info(u"%s: already Public, skippingi %s" % (uri, seq_label)) |
|
904 |
+ continue |
|
905 |
+ acl.grantAnonRead() |
|
906 |
+ else: |
|
907 |
+ if not acl.isAnonRead(): |
|
908 |
+ info(u"%s: already Private, skipping %s" % (uri, seq_label)) |
|
909 |
+ continue |
|
910 |
+ acl.revokeAnonRead() |
|
911 |
+ retsponse = s3.set_acl(uri, acl) |
|
912 |
+ if retsponse['status'] == 200: |
|
913 |
+ output(u"%s: ACL set to %s %s" % (uri, set_to_acl, seq_label)) |
|
914 |
+ |
|
888 | 915 |
def resolve_list(lst, args): |
889 | 916 |
retval = [] |
890 | 917 |
for item in lst: |
... | ... |
@@ -1085,7 +1112,7 @@ commands_list = [ |
1085 | 1085 |
{"cmd":"info", "label":"Get various information about Buckets or Objects", "param":"s3://BUCKET[/OBJECT]", "func":cmd_info, "argc":1}, |
1086 | 1086 |
{"cmd":"cp", "label":"Copy object", "param":"s3://BUCKET1/OBJECT1 s3://BUCKET2[/OBJECT2]", "func":cmd_cp, "argc":2}, |
1087 | 1087 |
{"cmd":"mv", "label":"Move object", "param":"s3://BUCKET1/OBJECT1 s3://BUCKET2[/OBJECT2]", "func":cmd_mv, "argc":2}, |
1088 |
- #{"cmd":"setacl", "label":"Modify Access control list for Bucket or Object", "param":"s3://BUCKET[/OBJECT]", "func":cmd_setacl, "argc":1}, |
|
1088 |
+ {"cmd":"setacl", "label":"Modify Access control list for Bucket or Object", "param":"s3://BUCKET[/OBJECT]", "func":cmd_setacl, "argc":1}, |
|
1089 | 1089 |
] |
1090 | 1090 |
|
1091 | 1091 |
def format_commands(progname): |