2
* Software License Agreement (BSD License)
4
* Copyright (c) 2008, Regents of the University of California
7
* Redistribution and use of this software in source and binary forms, with or
8
* without modification, are permitted provided that the following conditions
11
* * Redistributions of source code must retain the above
12
* copyright notice, this list of conditions and the
13
* following disclaimer.
15
* * Redistributions in binary form must reproduce the above
16
* copyright notice, this list of conditions and the
17
* following disclaimer in the documentation and/or other
18
* materials provided with the distribution.
20
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30
* POSSIBILITY OF SUCH DAMAGE.
32
* Author: Sunil Soman sunils@cs.ucsb.edu
35
package edu.ucsb.eucalyptus.cloud.ws;
37
import edu.ucsb.eucalyptus.cloud.*;
38
import edu.ucsb.eucalyptus.cloud.entities.*;
39
import edu.ucsb.eucalyptus.keys.*;
40
import edu.ucsb.eucalyptus.msgs.*;
41
import edu.ucsb.eucalyptus.storage.StorageManager;
42
import edu.ucsb.eucalyptus.storage.fs.FileSystemStorageManager;
43
import edu.ucsb.eucalyptus.transport.query.WalrusQueryDispatcher;
44
import edu.ucsb.eucalyptus.util.*;
45
import org.apache.log4j.Logger;
46
import org.apache.tools.ant.util.DateUtils;
47
import org.apache.tools.tar.*;
49
import javax.crypto.*;
50
import javax.crypto.spec.*;
52
import java.nio.ByteBuffer;
53
import java.nio.channels.*;
54
import java.security.*;
55
import java.security.cert.X509Certificate;
57
import java.util.concurrent.LinkedBlockingQueue;
58
import java.util.zip.GZIPInputStream;
62
private static Logger LOG = Logger.getLogger( Bukkit.class );
64
private static WalrusDataMessenger imageMessenger = new WalrusDataMessenger();
66
static StorageManager storageManager;
67
static boolean shouldEnforceUsageLimits = true;
70
storageManager = new FileSystemStorageManager();
71
String limits = System.getProperty(WalrusProperties.USAGE_LIMITS_PROPERTY);
73
shouldEnforceUsageLimits = Boolean.parseBoolean(limits);
80
public CreateBucketResponseType CreateBucket(CreateBucketType request) throws EucalyptusCloudException {
81
CreateBucketResponseType reply = (CreateBucketResponseType) request.getReply();
82
String userId = request.getUserId();
84
String bucketName = request.getBucket();
87
throw new AccessDeniedException(bucketName);
90
AccessControlListType accessControlList = request.getAccessControlList();
91
if (accessControlList == null) {
92
accessControlList = new AccessControlListType();
95
EntityWrapper<BucketInfo> db = new EntityWrapper<BucketInfo>();
97
if(shouldEnforceUsageLimits && !request.isAdministrator()) {
98
BucketInfo searchBucket = new BucketInfo();
99
searchBucket.setOwnerId(userId);
100
List<BucketInfo> bucketList = db.query(searchBucket);
101
if(bucketList.size() >= WalrusProperties.MAX_BUCKETS_PER_USER) {
103
throw new TooManyBucketsException(bucketName);
107
BucketInfo bucketInfo = new BucketInfo(bucketName);
108
List<BucketInfo> bucketList = db.query(bucketInfo);
110
if(bucketList.size() > 0) {
111
if(bucketList.get(0).getOwnerId().equals(userId)) {
112
//bucket already exists and you created it
114
throw new BucketAlreadyOwnedByYouException(bucketName);
116
//bucket already exists
118
throw new BucketAlreadyExistsException(bucketName);
120
//create bucket and set its acl
121
BucketInfo bucket = new BucketInfo(userId, bucketName, new Date());
122
ArrayList<GrantInfo> grantInfos = new ArrayList<GrantInfo>();
123
bucket.addGrants(userId, grantInfos, accessControlList);
124
bucket.setGrants(grantInfos);
125
bucket.setBucketSize(0L);
127
ArrayList<ObjectInfo> objectInfos = new ArrayList<ObjectInfo>();
128
bucket.setObjects(objectInfos);
129
//call the storage manager to save the bucket to disk
131
storageManager.createBucket(bucketName);
133
} catch (IOException ex) {
135
//TODO: set exception code in reply
140
reply.setBucket(bucketName);
144
public DeleteBucketResponseType DeleteBucket(DeleteBucketType request) throws EucalyptusCloudException {
145
DeleteBucketResponseType reply = (DeleteBucketResponseType) request.getReply();
147
String bucketName = request.getBucket();
149
String userId = request.getUserId();
151
EntityWrapper<BucketInfo> db = new EntityWrapper<BucketInfo>();
152
BucketInfo searchBucket = new BucketInfo(bucketName);
153
List<BucketInfo> bucketList = db.query(searchBucket);
156
if(bucketList.size() > 0) {
157
BucketInfo bucketFound = bucketList.get(0);
158
if (bucketFound.canWrite(userId)) {
159
List<ObjectInfo> objectInfos = bucketFound.getObjects();
160
if(objectInfos.size() == 0) {
161
db.delete(bucketFound);
162
//Actually remove the bucket from the backing store
164
storageManager.deleteBucket(bucketName);
165
} catch (IOException ex) {
166
//set exception code in reply
168
Status status = new Status();
170
status.setDescription("No Content");
171
reply.setStatus(status);
174
throw new BucketNotEmptyException(bucketName);
178
throw new AccessDeniedException(bucketName);
182
throw new NoSuchBucketException(bucketName);
188
public ListAllMyBucketsResponseType ListAllMyBuckets(ListAllMyBucketsType request) throws EucalyptusCloudException {
189
ListAllMyBucketsResponseType reply = (ListAllMyBucketsResponseType) request.getReply();
190
EntityWrapper<BucketInfo> db = new EntityWrapper<BucketInfo>();
191
String userId = request.getUserId();
194
throw new AccessDeniedException("no such user");
197
EntityWrapper<UserInfo> db2 = new EntityWrapper<UserInfo>();
198
UserInfo searchUser = new UserInfo(userId);
199
List<UserInfo> userInfoList = db2.query(searchUser);
201
if(userInfoList.size() > 0) {
202
UserInfo user = userInfoList.get(0);
203
BucketInfo searchBucket = new BucketInfo();
204
searchBucket.setOwnerId(userId);
205
List<BucketInfo> bucketInfoList = db.query(searchBucket);
207
ArrayList<BucketListEntry> buckets = new ArrayList<BucketListEntry>();
209
for(BucketInfo bucketInfo: bucketInfoList) {
210
buckets.add(new BucketListEntry(bucketInfo.getBucketName(), DateUtils.format(bucketInfo.getCreationDate().getTime(), DateUtils.ISO8601_DATETIME_PATTERN) + ".000Z"));
213
CanonicalUserType owner = new CanonicalUserType(user.getQueryId(), user.getUserName());
214
ListAllMyBucketsList bucketList = new ListAllMyBucketsList();
215
reply.setOwner(owner);
216
bucketList.setBuckets(buckets);
217
reply.setBucketList(bucketList);
220
throw new AccessDeniedException(userId);
226
public GetBucketAccessControlPolicyResponseType GetBucketAccessControlPolicy(GetBucketAccessControlPolicyType request) throws EucalyptusCloudException
228
GetBucketAccessControlPolicyResponseType reply = (GetBucketAccessControlPolicyResponseType) request.getReply();
230
String bucketName = request.getBucket();
231
String userId = request.getUserId();
232
String ownerId = null;
234
EntityWrapper<BucketInfo> db = new EntityWrapper<BucketInfo>();
235
BucketInfo bucketInfo = new BucketInfo(bucketName);
236
List<BucketInfo> bucketList = db.query(bucketInfo);
238
AccessControlListType accessControlList = new AccessControlListType();
240
if (bucketList.size() > 0) {
241
//construct access control policy from grant infos
242
BucketInfo bucket = bucketList.get(0);
243
List<GrantInfo> grantInfos = bucket.getGrants();
244
if (bucket.canReadACP(userId)) {
245
ownerId = bucket.getOwnerId();
246
ArrayList<Grant> grants = new ArrayList<Grant>();
247
for (GrantInfo grantInfo: grantInfos) {
248
String uId = grantInfo.getUserId();
249
UserInfo userInfo = new UserInfo(uId);
250
EntityWrapper<UserInfo> db2 = new EntityWrapper<UserInfo>();
251
List<UserInfo> grantUserInfos = db2.query(userInfo);
254
if(grantUserInfos.size() > 0) {
255
UserInfo grantUserInfo = grantUserInfos.get(0);
256
addPermission(grants, grantUserInfo, grantInfo);
259
accessControlList.setGrants(grants);
263
throw new NoSuchBucketException(bucketName);
265
UserInfo userInfo = new UserInfo(ownerId);
266
EntityWrapper<UserInfo> db2 = new EntityWrapper<UserInfo>();
267
List<UserInfo> ownerUserInfos = db2.query(userInfo);
270
AccessControlPolicyType accessControlPolicy = new AccessControlPolicyType();
271
if(ownerUserInfos.size() > 0) {
272
UserInfo ownerUserInfo = ownerUserInfos.get(0);
273
accessControlPolicy.setOwner(new CanonicalUserType(ownerUserInfo.getQueryId(), ownerUserInfo.getUserName()));
274
accessControlPolicy.setAccessControlList(accessControlList);
276
reply.setAccessControlPolicy(accessControlPolicy);
282
private static void addPermission(ArrayList<Grant>grants, UserInfo userInfo, GrantInfo grantInfo) {
283
CanonicalUserType user = new CanonicalUserType(userInfo.getQueryId(), userInfo.getUserName());
285
if (grantInfo.isRead() && grantInfo.isWrite() && grantInfo.isReadACP() && grantInfo.isWriteACP()) {
286
grants.add(new Grant(user, "FULL_CONTROL"));
290
if (grantInfo.isRead()) {
291
grants.add(new Grant(user, "READ"));
294
if (grantInfo.isWrite()) {
295
grants.add(new Grant(user, "WRITE"));
298
if (grantInfo.isReadACP()) {
299
grants.add(new Grant(user, "READ_ACP"));
302
if (grantInfo.isWriteACP()) {
303
grants.add(new Grant(user, "WRITE_ACP"));
307
public PutObjectResponseType PutObject (PutObjectType request) throws EucalyptusCloudException {
308
PutObjectResponseType reply = (PutObjectResponseType) request.getReply();
309
String userId = request.getUserId();
311
String bucketName = request.getBucket();
312
String objectName = request.getKey();
314
Long oldBucketSize = 0L;
317
Date lastModified = null;
319
AccessControlListType accessControlList = request.getAccessControlList();
320
if (accessControlList == null) {
321
accessControlList = new AccessControlListType();
324
EntityWrapper<BucketInfo> db = new EntityWrapper<BucketInfo>();
325
BucketInfo bucketInfo = new BucketInfo(bucketName);
326
List<BucketInfo> bucketList = db.query(bucketInfo);
328
if(bucketList.size() > 0) {
329
BucketInfo bucket = bucketList.get(0);
330
if (bucket.canWrite(userId)) {
332
ObjectInfo foundObject = null;
333
List<ObjectInfo> objectInfos = bucket.getObjects();
334
for (ObjectInfo objectInfo: objectInfos) {
335
if (objectInfo.getObjectName().equals(objectName)) {
336
//key (object) exists. check perms
337
if (!objectInfo.canWrite(userId)) {
339
throw new AccessDeniedException(objectName);
341
foundObject = objectInfo;
342
oldBucketSize = -foundObject.getSize();
346
//write object to bucket
347
if (foundObject == null) {
348
//not found. create an object info
349
foundObject = new ObjectInfo(objectName);
350
List<GrantInfo> grantInfos = new ArrayList<GrantInfo>();
351
foundObject.addGrants(userId, grantInfos, accessControlList);
352
foundObject.setGrants(grantInfos);
353
objectInfos.add(foundObject);
355
//object already exists. see if we can modify acl
356
if (foundObject.canWriteACP(userId)) {
357
List<GrantInfo> grantInfos = foundObject.getGrants();
358
foundObject.addGrants(userId, grantInfos, accessControlList);
361
foundObject.setObjectName(objectName);
362
foundObject.setOwnerId(userId);
363
foundObject.addMetaData(request.getMetaData());
364
//writes are unconditional
365
String randomKey = request.getRandomKey();
367
WalrusDataMessenger messenger = WalrusQueryDispatcher.getWriteMessenger();
368
String key = bucketName + "." + objectName;
369
LinkedBlockingQueue<WalrusDataMessage> putQueue = messenger.getQueue(key, randomKey);
372
WalrusDataMessage dataMessage = null;
373
String tempObjectName = objectName;
374
MessageDigest digest = null;
377
while ((dataMessage = putQueue.take())!=null) {
378
if(WalrusDataMessage.isStart(dataMessage)) {
379
tempObjectName = objectName + "." + Hashes.getRandom(12);
380
digest = Hashes.Digest.MD5.get();
381
} else if(WalrusDataMessage.isEOF(dataMessage)) {
384
storageManager.renameObject(bucketName, tempObjectName, objectName);
385
} catch (IOException ex) {
386
//TODO: error handling
389
md5 = bytesToHex(digest.digest());
390
lastModified = new Date();
391
foundObject.setEtag(md5);
392
foundObject.setSize(size);
393
foundObject.setLastModified(lastModified);
394
foundObject.setStorageClass("STANDARD");
395
if(shouldEnforceUsageLimits && !request.isAdministrator()) {
396
Long bucketSize = bucket.getBucketSize();
397
long newSize = bucketSize + oldBucketSize + size;
398
if(newSize > WalrusProperties.MAX_BUCKET_SIZE) {
400
throw new EntityTooLargeException(objectName);
402
bucket.setBucketSize(newSize);
405
//restart all interrupted puts
406
WalrusMonitor monitor = messenger.getMonitor(key);
407
synchronized (monitor) {
408
monitor.setLastModified(lastModified);
412
messenger.removeQueue(key, randomKey);
413
messenger.removeMonitor(key);
414
LOG.info("Transfer complete" + key + " " + randomKey);
417
} else if(WalrusDataMessage.isInterrupted(dataMessage)) {
419
//there was a write after this one started
420
//abort writing but wait until the other (last) writer has completed
421
WalrusMonitor monitor = messenger.getMonitor(key);
422
synchronized (monitor) {
424
lastModified = monitor.getLastModified();
425
md5 = monitor.getMd5();
427
//ok we are done here
429
storageManager.deleteObject(bucketName, tempObjectName);
430
} catch (IOException ex) {
431
ex.printStackTrace();
434
LOG.info("Transfer interrupted" + key + " " + randomKey);
437
assert(WalrusDataMessage.isData(dataMessage));
438
byte[] data = dataMessage.getPayload();
439
//start writing object (but do not committ yet)
441
storageManager.putObject(bucketName, tempObjectName, data, true);
442
} catch (IOException ex) {
445
//calculate md5 on the fly
450
} catch (InterruptedException ex) {
451
ex.printStackTrace();
452
throw new EucalyptusCloudException();
456
throw new AccessDeniedException(bucketName);
460
throw new NoSuchBucketException(bucketName);
463
reply.setLastModified(DateUtils.format(lastModified.getTime(), DateUtils.ISO8601_DATETIME_PATTERN) + ".000Z");
467
public PutObjectInlineResponseType PutObjectInline (PutObjectInlineType request) throws EucalyptusCloudException {
468
PutObjectInlineResponseType reply = (PutObjectInlineResponseType) request.getReply();
469
String userId = request.getUserId();
471
String bucketName = request.getBucket();
472
String objectName = request.getKey();
475
Long oldBucketSize = 0L;
476
Date lastModified = null;
478
AccessControlListType accessControlList = request.getAccessControlList();
479
if (accessControlList == null) {
480
accessControlList = new AccessControlListType();
483
EntityWrapper<BucketInfo> db = new EntityWrapper<BucketInfo>();
484
BucketInfo bucketInfo = new BucketInfo(bucketName);
485
List<BucketInfo> bucketList = db.query(bucketInfo);
487
if(bucketList.size() > 0) {
488
BucketInfo bucket = bucketList.get(0);
489
if (bucket.canWrite(userId)) {
490
ObjectInfo foundObject = null;
491
List<ObjectInfo> objectInfos = bucket.getObjects();
492
for (ObjectInfo objectInfo: objectInfos) {
493
if (objectInfo.getObjectName().equals(objectName)) {
494
//key (object) exists. check perms
495
if (!objectInfo.canWrite(userId)) {
497
throw new AccessDeniedException(objectName);
499
foundObject = objectInfo;
500
oldBucketSize = -foundObject.getSize();
504
//write object to bucket
505
if (foundObject == null) {
506
//not found. create an object info
507
foundObject = new ObjectInfo(objectName);
508
List<GrantInfo> grantInfos = new ArrayList<GrantInfo>();
509
foundObject.addGrants(userId, grantInfos, accessControlList);
510
foundObject.setGrants(grantInfos);
511
objectInfos.add(foundObject);
513
//object already exists. see if we can modify acl
514
if (foundObject.canWriteACP(userId)) {
515
List<GrantInfo> grantInfos = foundObject.getGrants();
516
foundObject.addGrants(userId, grantInfos, accessControlList);
519
foundObject.setObjectName(objectName);
520
foundObject.setOwnerId(userId);
522
//writes are unconditional
523
byte[] base64Data = request.getBase64Data().getBytes();
524
storageManager.putObject(bucketName, objectName, base64Data, false);
525
md5 = Hashes.getHexString(Hashes.Digest.MD5.get().digest(base64Data));
526
foundObject.setEtag(md5);
527
Long size = Long.parseLong(request.getContentLength());
528
foundObject.setSize(size);
529
if(shouldEnforceUsageLimits && !request.isAdministrator()) {
530
Long bucketSize = bucket.getBucketSize();
531
long newSize = bucketSize + oldBucketSize + size;
532
if(newSize > WalrusProperties.MAX_BUCKET_SIZE) {
534
throw new EntityTooLargeException(objectName);
536
bucket.setBucketSize(newSize);
538
//Add meta data if specified
539
foundObject.addMetaData(request.getMetaData());
541
//TODO: add support for other storage classes
542
foundObject.setStorageClass("STANDARD");
543
lastModified = new Date();
544
foundObject.setLastModified(lastModified);
545
} catch (IOException ex) {
546
//TODO: set error code
551
throw new AccessDeniedException(bucketName);
556
throw new NoSuchBucketException(bucketName);
562
reply.setLastModified(DateUtils.format(lastModified.getTime(), DateUtils.ISO8601_DATETIME_PATTERN) + ".000Z");
566
public DeleteObjectResponseType DeleteObject (DeleteObjectType request) throws EucalyptusCloudException {
567
DeleteObjectResponseType reply = (DeleteObjectResponseType) request.getReply();
568
String bucketName = request.getBucket();
569
String objectName = request.getKey();
570
String userId = request.getUserId();
572
EntityWrapper<BucketInfo> db = new EntityWrapper<BucketInfo>();
573
BucketInfo bucketInfos = new BucketInfo(bucketName);
574
List<BucketInfo> bucketList = db.query(bucketInfos);
576
if (bucketList.size() > 0) {
577
BucketInfo bucketInfo = bucketList.get(0);
578
ObjectInfo foundObject = null;
580
for (ObjectInfo objectInfo: bucketInfo.getObjects()) {
581
if (objectInfo.getObjectName().equals(objectName)) {
582
foundObject = objectInfo;
586
if (foundObject != null) {
587
if (foundObject.canWrite(userId)) {
588
bucketInfo.getObjects().remove(foundObject);
589
for (GrantInfo grantInfo: foundObject.getGrants()) {
590
db.getEntityManager().remove(grantInfo);
592
Long size = foundObject.getSize();
593
bucketInfo.setBucketSize(bucketInfo.getBucketSize() - size);
594
db.getEntityManager().remove(foundObject);
596
storageManager.deleteObject(bucketName, objectName);
597
} catch (IOException ex) {
598
//TODO: set error code
601
reply.setCode("200");
602
reply.setDescription("OK");
605
throw new AccessDeniedException(objectName);
609
throw new AccessDeniedException(objectName);
613
throw new NoSuchBucketException(bucketName);
619
public ListBucketResponseType ListBucket(ListBucketType request) throws EucalyptusCloudException {
620
ListBucketResponseType reply = (ListBucketResponseType) request.getReply();
621
String bucketName = request.getBucket();
622
String userId = request.getUserId();
623
String prefix = request.getPrefix();
624
String marker = request.getMarker();
627
String maxKeysString = request.getMaxKeys();
628
if(maxKeysString != null)
629
maxKeys = Integer.parseInt(maxKeysString);
631
String delimiter = request.getDelimiter();
633
EntityWrapper<BucketInfo> db = new EntityWrapper<BucketInfo>();
634
BucketInfo bucketInfo = new BucketInfo(bucketName);
635
List<BucketInfo> bucketList = db.query(bucketInfo);
637
ArrayList<PrefixEntry> prefixes = new ArrayList<PrefixEntry>();
639
if(bucketList.size() > 0) {
640
BucketInfo bucket = bucketList.get(0);
641
if(bucket.canRead(userId)) {
642
reply.setName(bucketName);
643
reply.setIsTruncated(false);
645
reply.setMaxKeys(maxKeys);
647
reply.setPrefix(prefix);
650
reply.setMarker(marker);
651
if(delimiter != null)
652
reply.setDelimiter(delimiter);
653
List<ObjectInfo> objectInfos = bucket.getObjects();
654
if(objectInfos.size() > 0) {
655
int howManyProcessed = 0;
656
ArrayList<ListEntry> contents = new ArrayList<ListEntry>();
657
for(ObjectInfo objectInfo: objectInfos) {
658
String objectName = objectInfo.getObjectName();
660
if(objectName.compareTo(marker) < 0)
664
if(!objectName.startsWith(prefix)) {
667
if(delimiter != null) {
668
String[] parts = objectName.substring(prefix.length()).split(delimiter);
669
if(parts.length > 1) {
670
String prefixString = parts[0] + delimiter;
671
boolean foundPrefix = false;
672
for(PrefixEntry prefixEntry : prefixes) {
673
if(prefixEntry.getPrefix().equals(prefixString)) {
679
prefixes.add(new PrefixEntry(prefixString));
681
if(howManyProcessed++ > maxKeys) {
682
reply.setIsTruncated(true);
693
if(howManyProcessed++ > maxKeys) {
694
reply.setIsTruncated(true);
698
ListEntry listEntry = new ListEntry();
699
listEntry.setKey(objectName);
700
listEntry.setEtag(objectInfo.getEtag());
701
listEntry.setLastModified(DateUtils.format(objectInfo.getLastModified().getTime(), DateUtils.ISO8601_DATETIME_PATTERN) + ".000Z");
702
listEntry.setStorageClass(objectInfo.getStorageClass());
703
String displayName = objectInfo.getOwnerId();
705
EntityWrapper<UserInfo> db2 = new EntityWrapper<UserInfo>();
706
UserInfo userInfo = new UserInfo(displayName);
707
List<UserInfo> ownerInfos = db2.query(userInfo);
709
if(ownerInfos.size() > 0) {
710
listEntry.setOwner(new CanonicalUserType(ownerInfos.get(0).getQueryId(), displayName));
712
ArrayList<MetaDataEntry> metaData = new ArrayList<MetaDataEntry>();
713
objectInfo.getMetaData(metaData);
714
reply.setMetaData(metaData);
715
listEntry.setSize(objectInfo.getSize());
716
listEntry.setStorageClass(objectInfo.getStorageClass());
717
contents.add(listEntry);
719
reply.setContents(contents);
721
reply.setCommonPrefixes(prefixes);
726
throw new AccessDeniedException(bucketName);
730
throw new NoSuchBucketException(bucketName);
736
public GetObjectAccessControlPolicyResponseType GetObjectAccessControlPolicy(GetObjectAccessControlPolicyType request) throws EucalyptusCloudException
738
GetObjectAccessControlPolicyResponseType reply = (GetObjectAccessControlPolicyResponseType) request.getReply();
740
String bucketName = request.getBucket();
741
String objectName = request.getKey();
742
String userId = request.getUserId();
743
String ownerId = null;
745
EntityWrapper<BucketInfo> db = new EntityWrapper<BucketInfo>();
746
BucketInfo bucketInfo = new BucketInfo(bucketName);
747
List<BucketInfo> bucketList = db.query(bucketInfo);
749
AccessControlListType accessControlList = new AccessControlListType();
751
if (bucketList.size() > 0) {
752
//construct access control policy from grant infos
753
BucketInfo bucket = bucketList.get(0);
754
for(ObjectInfo objectInfo: bucket.getObjects()) {
755
if (objectInfo.getObjectName().equals(objectName)) {
756
if(objectInfo.canReadACP(userId)) {
757
ownerId = objectInfo.getOwnerId();
758
ArrayList<Grant> grants = new ArrayList<Grant>();
759
List<GrantInfo> grantInfos = objectInfo.getGrants();
760
for (GrantInfo grantInfo: grantInfos) {
761
String uId = grantInfo.getUserId();
762
UserInfo userInfo = new UserInfo(uId);
763
EntityWrapper<UserInfo> db2 = new EntityWrapper<UserInfo>();
764
List<UserInfo> grantUserInfos = db2.query(userInfo);
766
if(grantUserInfos.size() > 0) {
767
addPermission(grants, grantUserInfos.get(0), grantInfo);
770
accessControlList.setGrants(grants);
773
throw new AccessDeniedException(objectName);
780
throw new NoSuchBucketException(bucketName);
782
UserInfo userInfo = new UserInfo(ownerId);
783
EntityWrapper<UserInfo> db2 = new EntityWrapper<UserInfo>();
784
List<UserInfo> ownerUserInfos = db2.query(userInfo);
787
AccessControlPolicyType accessControlPolicy = new AccessControlPolicyType();
788
if(ownerUserInfos.size() > 0) {
789
UserInfo ownerUserInfo = ownerUserInfos.get(0);
790
accessControlPolicy.setOwner(new CanonicalUserType(ownerUserInfo.getQueryId(), ownerUserInfo.getUserName()));
791
accessControlPolicy.setAccessControlList(accessControlList);
792
reply.setAccessControlPolicy(accessControlPolicy);
798
public SetBucketAccessControlPolicyResponseType SetBucketAccessControlPolicy(SetBucketAccessControlPolicyType request) throws EucalyptusCloudException
800
SetBucketAccessControlPolicyResponseType reply = (SetBucketAccessControlPolicyResponseType) request.getReply();
801
String userId = request.getUserId();
802
AccessControlPolicyType accessControlPolicy = request.getAccessControlPolicy();
803
if(accessControlPolicy == null) {
804
throw new AccessDeniedException(userId);
806
String bucketName = request.getBucket();
808
EntityWrapper<BucketInfo> db = new EntityWrapper<BucketInfo>();
809
BucketInfo bucketInfo = new BucketInfo(bucketName);
810
List<BucketInfo> bucketList = db.query(bucketInfo);
812
if (bucketList.size() > 0) {
813
BucketInfo bucket = bucketList.get(0);
814
if (bucket.canWriteACP(userId) && accessControlPolicy.getOwner().getDisplayName().equals(bucket.getOwnerId())) {
815
List<GrantInfo> grantInfos = new ArrayList<GrantInfo>();
816
AccessControlListType accessControlList = accessControlPolicy.getAccessControlList();
817
bucket.resetGlobalGrants();
818
bucket.addGrants(bucket.getOwnerId(), grantInfos, accessControlList);
819
bucket.setGrants(grantInfos);
820
reply.setCode("204");
821
reply.setDescription("OK");
824
throw new AccessDeniedException(bucketName);
828
throw new NoSuchBucketException(bucketName);
834
public SetObjectAccessControlPolicyResponseType SetObjectAccessControlPolicy(SetObjectAccessControlPolicyType request) throws EucalyptusCloudException
836
SetObjectAccessControlPolicyResponseType reply = (SetObjectAccessControlPolicyResponseType) request.getReply();
837
String userId = request.getUserId();
838
AccessControlPolicyType accessControlPolicy = request.getAccessControlPolicy();
839
String bucketName = request.getBucket();
840
String objectName = request.getKey();
842
EntityWrapper<BucketInfo> db = new EntityWrapper<BucketInfo>();
843
BucketInfo bucketInfo = new BucketInfo(bucketName);
844
List<BucketInfo> bucketList = db.query(bucketInfo);
846
if (bucketList.size() > 0) {
847
BucketInfo bucket = bucketList.get(0);
848
ObjectInfo foundObject = null;
849
for(ObjectInfo objectInfo: bucket.getObjects()) {
850
if(objectInfo.getObjectName().equals(objectName)) {
851
if (objectInfo.canWriteACP(userId) && accessControlPolicy.getOwner().getDisplayName().equals(objectInfo.getOwnerId())) {
852
foundObject = objectInfo;
856
throw new AccessDeniedException(objectName);
861
if(foundObject != null) {
862
List<GrantInfo> grantInfos = new ArrayList<GrantInfo>();
863
AccessControlListType accessControlList = accessControlPolicy.getAccessControlList();
864
foundObject.resetGlobalGrants();
865
foundObject.addGrants(foundObject.getOwnerId(), grantInfos, accessControlList);
866
foundObject.setGrants(grantInfos);
868
reply.setCode("204");
869
reply.setDescription("OK");
872
throw new NoSuchEntityException(objectName);
876
throw new NoSuchBucketException(bucketName);
882
public GetObjectResponseType GetObject(GetObjectType request) throws EucalyptusCloudException {
883
GetObjectResponseType reply = (GetObjectResponseType) request.getReply();
884
String bucketName = request.getBucket();
885
String objectName = request.getKey();
886
String userId = request.getUserId();
888
EntityWrapper<BucketInfo> db = new EntityWrapper<BucketInfo>();
889
BucketInfo bucketInfo = new BucketInfo(bucketName);
890
List<BucketInfo> bucketList = db.query(bucketInfo);
892
if (bucketList.size() > 0) {
893
BucketInfo bucket = bucketList.get(0);
895
for(ObjectInfo objectInfo: bucket.getObjects()) {
896
if(objectInfo.getObjectName().equals(objectName)) {
897
if(objectInfo.canRead(userId)) {
898
if(request.getGetMetaData()) {
899
ArrayList<MetaDataEntry> metaData = new ArrayList<MetaDataEntry>();
900
objectInfo.getMetaData(metaData);
901
reply.setMetaData(metaData);
903
if(request.getGetData()) {
904
if(request.getInlineData()) {
906
byte[] bytes = new byte[WalrusQueryDispatcher.DATA_MESSAGE_SIZE];
908
String base64Data = "";
909
while((bytesRead = storageManager.readObject(bucketName, objectName, bytes, bytesRead)) > 0) {
910
base64Data += new String(bytes, 0, bytesRead);
912
reply.setBase64Data(base64Data);
913
} catch (IOException ex) {
919
//support for large objects
920
String key = bucketName + "." + objectName;
921
String randomKey = key + "." + Hashes.getRandom(10);
922
request.setRandomKey(randomKey);
923
LinkedBlockingQueue<WalrusDataMessage> getQueue = WalrusQueryDispatcher.getReadMessenger().getQueue(key, randomKey);
925
Reader reader = new Reader(bucketName, objectName, objectInfo.getSize(), getQueue);
929
reply.setEtag(objectInfo.getEtag());
930
reply.setLastModified(DateUtils.format(objectInfo.getLastModified().getTime(), DateUtils.ISO8601_DATETIME_PATTERN) + ".000Z");
931
reply.setSize(objectInfo.getSize());
932
Status status = new Status();
934
status.setDescription("OK");
935
reply.setStatus(status);
938
throw new AccessDeniedException(objectName);
944
throw new NoSuchBucketException(bucketName);
950
public GetObjectExtendedResponseType GetObjectExtended(GetObjectExtendedType request) throws EucalyptusCloudException {
951
GetObjectExtendedResponseType reply = (GetObjectExtendedResponseType) request.getReply();
952
long byteRangeStart = request.getByteRangeStart();
953
long byteRangeEnd = request.getByteRangeEnd();
954
Date ifModifiedSince = request.getIfModifiedSince();
955
Date ifUnmodifiedSince = request.getIfUnmodifiedSince();
956
String ifMatch = request.getIfMatch();
957
String ifNoneMatch = request.getIfNoneMatch();
958
boolean returnCompleteObjectOnFailure = request.getReturnCompleteObjectOnConditionFailure();
960
String bucketName = request.getBucket();
961
String objectName = request.getKey();
962
String userId = request.getUserId();
963
Status status = new Status();
965
EntityWrapper<BucketInfo> db = new EntityWrapper<BucketInfo>();
966
BucketInfo bucketInfo = new BucketInfo(bucketName);
967
List<BucketInfo> bucketList = db.query(bucketInfo);
970
if (bucketList.size() > 0) {
971
BucketInfo bucket = bucketList.get(0);
973
for(ObjectInfo objectInfo: bucket.getObjects()) {
974
if(objectInfo.getObjectName().equals(objectName)) {
975
if(objectInfo.canRead(userId)) {
976
String etag = objectInfo.getEtag();
977
if(ifMatch != null) {
978
if(!ifMatch.equals(etag) && !returnCompleteObjectOnFailure) {
980
throw new PreconditionFailedException(etag);
984
if(ifNoneMatch != null) {
985
if(ifNoneMatch.equals(etag) && !returnCompleteObjectOnFailure) {
987
throw new NotModifiedException(etag);
990
Date lastModified = objectInfo.getLastModified();
991
if(ifModifiedSince != null) {
992
if((ifModifiedSince.getTime() >= lastModified.getTime()) && !returnCompleteObjectOnFailure) {
994
throw new NotModifiedException(lastModified.toString());
997
if(ifUnmodifiedSince != null) {
998
if((ifUnmodifiedSince.getTime() <= lastModified.getTime()) && !returnCompleteObjectOnFailure) {
1000
throw new PreconditionFailedException(lastModified.toString());
1003
if(request.getGetMetaData()) {
1004
ArrayList<MetaDataEntry> metaData = new ArrayList<MetaDataEntry>();
1005
objectInfo.getMetaData(metaData);
1006
reply.setMetaData(metaData);
1008
if(request.getGetData()) {
1009
String key = bucketName + "." + objectName;
1010
String randomKey = key + "." + Hashes.getRandom(10);
1011
request.setRandomKey(randomKey);
1012
LinkedBlockingQueue<WalrusDataMessage> getQueue = WalrusQueryDispatcher.getReadMessenger().getQueue(key, randomKey);
1014
Reader reader = new Reader(bucketName, objectName, objectInfo.getSize(), getQueue, byteRangeStart, byteRangeEnd);
1017
reply.setEtag(objectInfo.getEtag());
1018
reply.setLastModified(DateUtils.format(objectInfo.getLastModified().getTime(), DateUtils.ISO8601_DATETIME_PATTERN) + ".000Z");
1019
reply.setSize(objectInfo.getSize());
1020
status.setCode(200);
1021
status.setDescription("OK");
1022
reply.setStatus(status);
1025
throw new AccessDeniedException(objectName);
1034
public GetBucketLocationResponseType GetBucketLocation(GetBucketLocationType request) throws EucalyptusCloudException {
1035
GetBucketLocationResponseType reply = (GetBucketLocationResponseType) request.getReply();
1036
String bucketName = request.getBucket();
1037
String userId = request.getUserId();
1039
EntityWrapper<BucketInfo> db = new EntityWrapper<BucketInfo>();
1040
BucketInfo bucketInfo = new BucketInfo(bucketName);
1041
List<BucketInfo> bucketList = db.query(bucketInfo);
1043
if(bucketList.size() > 0) {
1044
BucketInfo bucket = bucketList.get(0);
1045
if(bucket.canRead(userId)) {
1046
String location = bucket.getLocation();
1047
if(location == null) {
1048
location = "NotSupported";
1050
reply.setLocationConstraint(location);
1053
throw new AccessDeniedException(userId);
1057
throw new NoSuchBucketException(bucketName);
1063
public CopyObjectResponseType CopyObject(CopyObjectType request) throws EucalyptusCloudException {
1064
CopyObjectResponseType reply = (CopyObjectResponseType) request.getReply();
1066
throw new NotImplementedException("CopyObject");
1069
public GetBucketLoggingStatusResponseType GetBucketLoggingStatus(GetBucketLoggingStatusType request) throws EucalyptusCloudException {
1070
GetBucketLoggingStatusResponseType reply = (GetBucketLoggingStatusResponseType) request.getReply();
1072
throw new NotImplementedException("GetBucketLoggingStatus");
1075
public SetBucketLoggingStatusResponseType SetBucketLoggingStatus(SetBucketLoggingStatusType request) throws EucalyptusCloudException {
1076
SetBucketLoggingStatusResponseType reply = (SetBucketLoggingStatusResponseType) request.getReply();
1078
throw new NotImplementedException("SetBucketLoggingStatus");
1081
private boolean canVerifySignature(Signature sigVerifier, X509Certificate cert, String signature, String verificationString) throws Exception {
1082
PublicKey publicKey = cert.getPublicKey();
1083
sigVerifier.initVerify(publicKey);
1084
sigVerifier.update((verificationString).getBytes());
1085
return sigVerifier.verify(hexToBytes(signature));
1088
private String decryptImage(String bucketName, String objectName, String userId, boolean isAdministrator) throws EucalyptusCloudException {
1089
EntityWrapper<BucketInfo> db = new EntityWrapper<BucketInfo>();
1090
BucketInfo bucketInfo = new BucketInfo(bucketName);
1091
List<BucketInfo> bucketList = db.query(bucketInfo);
1094
if (bucketList.size() > 0) {
1095
BucketInfo bucket = bucketList.get(0);
1097
for(ObjectInfo objectInfo: bucket.getObjects()) {
1098
if(objectInfo.getObjectName().equals(objectName)) {
1099
if(objectInfo.canRead(userId)) {
1100
File file = new File(storageManager.getObjectPath(bucketName, objectName));
1101
XMLParser parser = new XMLParser(file);
1103
String imageKey = parser.getValue("//image/name");
1104
String encryptedKey = parser.getValue("//ec2_encrypted_key");
1105
String encryptedIV = parser.getValue("//ec2_encrypted_iv");
1106
String signature = parser.getValue("//signature");
1108
AbstractKeyStore userKeyStore = UserKeyStore.getInstance();
1110
String image = parser.getXML("image");
1111
String machineConfiguration = parser.getXML("machine_configuration");
1113
String verificationString = machineConfiguration + image;
1115
Signature sigVerifier;
1117
sigVerifier = Signature.getInstance("SHA1withRSA");
1118
} catch (NoSuchAlgorithmException ex) {
1120
throw new DecryptionFailedException("SHA1withRSA not found");
1123
EntityWrapper<UserInfo> db2 = new EntityWrapper<UserInfo>();
1124
UserInfo userInfo = new UserInfo(userId);
1125
List<UserInfo> foundUserInfos = db2.query(userInfo);
1126
if(foundUserInfos.size() == 0) {
1129
throw new AccessDeniedException(userId);
1132
if(isAdministrator) {
1134
boolean verified = false;
1135
List<String> aliases = userKeyStore.getAliases();
1136
for(String alias : aliases) {
1137
X509Certificate cert = userKeyStore.getCertificate(alias);
1138
verified = canVerifySignature(sigVerifier, cert, signature, verificationString);
1143
throw new NotAuthorizedException("Invalid signature");
1145
} catch (Exception ex) {
1149
throw new DecryptionFailedException("signature verification");
1152
List<CertificateInfo> certInfos = foundUserInfos.get(0).getCertificates();
1153
boolean signatureVerified = false;
1154
for(CertificateInfo certInfo: certInfos) {
1155
String alias = certInfo.getCertAlias();
1157
X509Certificate cert = userKeyStore.getCertificate(alias);
1158
signatureVerified = canVerifySignature(sigVerifier, cert, signature, verificationString);
1159
if (signatureVerified)
1161
} catch(Exception ex) {
1165
throw new DecryptionFailedException("signature verification");
1168
if(!signatureVerified) {
1169
throw new NotAuthorizedException("Invalid signature");
1172
List<String> parts = parser.getValues("//image/parts/part/filename");
1173
ArrayList<String> qualifiedPaths = new ArrayList<String>();
1175
for (String part: parts) {
1176
qualifiedPaths.add(storageManager.getObjectPath(bucketName, part));
1179
String encryptedImageKey = imageKey + "-" + Hashes.getRandom(5) + ".crypt.gz";
1180
String encryptedImageName = storageManager.getObjectPath(bucketName, encryptedImageKey);
1181
String decryptedImageKey = encryptedImageKey.replaceAll("crypt.gz", "tgz");
1182
String decryptedImageName = storageManager.getObjectPath(bucketName, decryptedImageKey);
1183
assembleParts(encryptedImageName, qualifiedPaths);
1184
//Decrypt key and IV
1189
PrivateKey pk = (PrivateKey) userKeyStore.getKey(EucalyptusProperties.NAME, EucalyptusProperties.NAME);
1190
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
1191
cipher.init(Cipher.DECRYPT_MODE, pk);
1192
key = hexToBytes(new String(cipher.doFinal(hexToBytes(encryptedKey))));
1193
iv = hexToBytes(new String(cipher.doFinal(hexToBytes(encryptedIV))));
1194
} catch(Exception ex) {
1198
throw new DecryptionFailedException("AES params");
1203
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
1204
IvParameterSpec salt = new IvParameterSpec(iv);
1205
SecretKey keySpec = new SecretKeySpec(key, "AES");
1206
cipher.init(Cipher.DECRYPT_MODE, keySpec, salt);
1207
decryptImage(encryptedImageName, decryptedImageName, cipher);
1208
} catch (Exception ex) {
1212
throw new DecryptionFailedException("decryption failed");
1215
storageManager.deleteAbsoluteObject(encryptedImageName);
1216
} catch (Exception ex) {
1218
throw new EucalyptusCloudException();
1222
return decryptedImageKey;
1230
private void checkManifest(String bucketName, String objectName, String userId) throws EucalyptusCloudException {
1231
EntityWrapper<BucketInfo> db = new EntityWrapper<BucketInfo>();
1232
BucketInfo bucketInfo = new BucketInfo(bucketName);
1233
List<BucketInfo> bucketList = db.query(bucketInfo);
1236
if (bucketList.size() > 0) {
1237
BucketInfo bucket = bucketList.get(0);
1239
for(ObjectInfo objectInfo: bucket.getObjects()) {
1240
if(objectInfo.getObjectName().equals(objectName)) {
1241
if(objectInfo.canRead(userId)) {
1242
File file = new File(storageManager.getObjectPath(bucketName, objectName));
1243
XMLParser parser = new XMLParser(file);
1245
String imageKey = parser.getValue("//image/name");
1246
String encryptedKey = parser.getValue("//ec2_encrypted_key");
1247
String encryptedIV = parser.getValue("//ec2_encrypted_iv");
1248
String signature = parser.getValue("//signature");
1250
AbstractKeyStore userKeyStore = UserKeyStore.getInstance();
1252
String image = parser.getXML("image");
1253
String machineConfiguration = parser.getXML("machine_configuration");
1255
EntityWrapper<UserInfo> db2 = new EntityWrapper<UserInfo>();
1256
UserInfo userInfo = new UserInfo(userId);
1257
List<UserInfo> foundUserInfos = db2.query(userInfo);
1258
if(foundUserInfos.size() == 0) {
1261
throw new AccessDeniedException(userId);
1264
List<CertificateInfo> certInfos = foundUserInfos.get(0).getCertificates();
1265
boolean signatureVerified = false;
1267
Signature sigVerifier;
1269
sigVerifier = Signature.getInstance("SHA1withRSA");
1270
} catch (NoSuchAlgorithmException ex) {
1272
throw new DecryptionFailedException("SHA1withRSA not found");
1275
for(CertificateInfo certInfo: certInfos) {
1276
String alias = certInfo.getCertAlias();
1278
X509Certificate cert = (X509Certificate) userKeyStore.getCertificate(alias);
1279
PublicKey publicKey = cert.getPublicKey();
1280
sigVerifier.initVerify(publicKey);
1281
sigVerifier.update((machineConfiguration + image).getBytes());
1282
signatureVerified = sigVerifier.verify(hexToBytes(signature));
1283
if (signatureVerified) {
1286
} catch(Exception ex) {
1290
throw new DecryptionFailedException("signature verification");
1294
if(!signatureVerified) {
1295
throw new NotAuthorizedException("Invalid signature");
1297
//Decrypt key and IV
1302
PrivateKey pk = (PrivateKey) userKeyStore.getKey(EucalyptusProperties.NAME, EucalyptusProperties.NAME);
1303
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
1304
cipher.init(Cipher.DECRYPT_MODE, pk);
1305
key = hexToBytes(new String(cipher.doFinal(hexToBytes(encryptedKey))));
1306
iv = hexToBytes(new String(cipher.doFinal(hexToBytes(encryptedIV))));
1307
} catch(Exception ex) {
1311
throw new DecryptionFailedException("AES params");
1321
public GetDecryptedImageResponseType GetDecryptedImage(GetDecryptedImageType request) throws EucalyptusCloudException {
1322
GetDecryptedImageResponseType reply = (GetDecryptedImageResponseType) request.getReply();
1323
String bucketName = request.getBucket();
1324
String objectName = request.getKey();
1325
String userId = request.getUserId();
1327
EntityWrapper<BucketInfo> db = new EntityWrapper<BucketInfo>();
1328
BucketInfo bucketInfo = new BucketInfo(bucketName);
1329
List<BucketInfo> bucketList = db.query(bucketInfo);
1331
if (bucketList.size() > 0) {
1332
BucketInfo bucket = bucketList.get(0);
1334
for(ObjectInfo objectInfo: bucket.getObjects()) {
1335
if(objectInfo.getObjectName().equals(objectName)) {
1336
if(objectInfo.canRead(userId) || request.isAdministrator() ) {
1337
WalrusSemaphore semaphore = imageMessenger.getSemaphore(bucketName + "/" + objectName);
1339
semaphore.acquire();
1340
} catch(InterruptedException ex) {
1341
throw new EucalyptusCloudException("semaphore could not be acquired");
1343
EntityWrapper<ImageCacheInfo> db2 = new EntityWrapper<ImageCacheInfo>();
1344
ImageCacheInfo searchImageCacheInfo = new ImageCacheInfo(bucketName, objectName);
1345
List<ImageCacheInfo> foundImageCacheInfos = db2.query(searchImageCacheInfo);
1347
if(foundImageCacheInfos.size() == 0) {
1349
//issue a cache request
1350
cacheImage(bucketName, objectName, userId, request.isAdministrator());
1352
db2 = new EntityWrapper<ImageCacheInfo>();
1353
foundImageCacheInfos = db2.query(searchImageCacheInfo);
1355
ImageCacheInfo foundImageCacheInfo = foundImageCacheInfos.get(0);
1356
if(!foundImageCacheInfo.getInCache()) {
1357
WalrusMonitor monitor = imageMessenger.getMonitor(bucketName + "/" + objectName);
1358
synchronized (monitor) {
1361
} catch(Exception ex) {
1365
throw new EucalyptusCloudException("monitor failure");
1368
//caching may have modified the db. repeat the query
1370
db2 = new EntityWrapper<ImageCacheInfo>();
1371
foundImageCacheInfos = db2.query(searchImageCacheInfo);
1372
if(foundImageCacheInfos.size() > 0) {
1373
foundImageCacheInfo = foundImageCacheInfos.get(0);
1374
foundImageCacheInfo.setUseCount(foundImageCacheInfo.getUseCount() + 1);
1375
assert(foundImageCacheInfo.getInCache());
1379
throw new NoSuchEntityException(objectName);
1383
Long unencryptedSize = foundImageCacheInfo.getSize();
1384
String imageKey = foundImageCacheInfo.getImageName();
1385
String queueKey = bucketName + "." + objectName;
1386
String randomKey = queueKey + "." + Hashes.getRandom(10);
1387
request.setRandomKey(randomKey);
1389
LinkedBlockingQueue<WalrusDataMessage> getQueue = WalrusQueryDispatcher.getReadMessenger().getQueue(queueKey, randomKey);
1390
reply.setSize(unencryptedSize);
1391
reply.setLastModified(DateUtils.format(objectInfo.getLastModified().getTime(), DateUtils.ISO8601_DATETIME_PATTERN) + ".000Z");
1393
Reader reader = new Reader(bucketName, imageKey, unencryptedSize, getQueue, false, semaphore);
1400
throw new AccessDeniedException(objectName);
1405
throw new NoSuchEntityException(objectName);
1408
throw new NoSuchBucketException(bucketName);
1412
public CheckImageResponseType CheckImage(CheckImageType request) throws EucalyptusCloudException {
1413
CheckImageResponseType reply = (CheckImageResponseType) request.getReply();
1414
reply.setSuccess(false);
1415
String bucketName = request.getBucket();
1416
String objectName = request.getKey();
1417
String userId = request.getUserId();
1419
EntityWrapper<BucketInfo> db = new EntityWrapper<BucketInfo>();
1420
BucketInfo bucketInfo = new BucketInfo(bucketName);
1421
List<BucketInfo> bucketList = db.query(bucketInfo);
1424
if (bucketList.size() > 0) {
1425
BucketInfo bucket = bucketList.get(0);
1427
for(ObjectInfo objectInfo: bucket.getObjects()) {
1428
if(objectInfo.getObjectName().equals(objectName)) {
1429
if(objectInfo.canRead(userId)) {
1430
checkManifest(bucketName, objectName, userId);
1431
reply.setSuccess(true);
1436
throw new AccessDeniedException(objectName);
1441
throw new NoSuchEntityException(objectName);
1444
throw new NoSuchBucketException(bucketName);
1448
private void cacheImage(String bucketName, String manifestKey, String userId, boolean isAdministrator) throws EucalyptusCloudException {
1449
EntityWrapper<ImageCacheInfo> db = new EntityWrapper<ImageCacheInfo>();
1450
ImageCacheInfo searchImageCacheInfo = new ImageCacheInfo(bucketName, manifestKey);
1451
List<ImageCacheInfo> imageCacheInfos = db.query(searchImageCacheInfo);
1453
if(imageCacheInfos.size() == 0) {
1454
String decryptedImageKey = decryptImage(bucketName, manifestKey, userId, isAdministrator);
1455
//decryption worked. Add it.
1456
ImageCacheInfo foundImageCacheInfo = new ImageCacheInfo(bucketName, manifestKey);
1457
foundImageCacheInfo.setImageName(decryptedImageKey);
1458
foundImageCacheInfo.setInCache(false);
1459
foundImageCacheInfo.setCaching(true);
1460
foundImageCacheInfo.setUseCount(0);
1461
foundImageCacheInfo.setSize(0L);
1462
db.add(foundImageCacheInfo);
1464
//decrypt, unzip, untar image in the background
1465
ImageCacher imageCacher = new ImageCacher(bucketName, manifestKey, decryptedImageKey);
1469
throw new ImageAlreadyExistsException(manifestKey);
1473
public CacheImageResponseType CacheImage(CacheImageType request) throws EucalyptusCloudException {
1474
CacheImageResponseType reply = (CacheImageResponseType) request.getReply();
1475
reply.setSuccess(false);
1476
String bucketName = request.getBucket();
1477
String manifestKey = request.getKey();
1478
String userId = request.getUserId();
1480
EntityWrapper<BucketInfo> db = new EntityWrapper<BucketInfo>();
1481
BucketInfo bucketInfo = new BucketInfo(bucketName);
1482
List<BucketInfo> bucketList = db.query(bucketInfo);
1485
if (bucketList.size() > 0) {
1486
BucketInfo bucket = bucketList.get(0);
1488
for(ObjectInfo objectInfo: bucket.getObjects()) {
1489
if(objectInfo.getObjectName().equals(manifestKey)) {
1490
if(objectInfo.canRead(userId)) {
1491
EntityWrapper<ImageCacheInfo> db2 = new EntityWrapper<ImageCacheInfo>();
1492
ImageCacheInfo searchImageCacheInfo = new ImageCacheInfo(bucketName, manifestKey);
1493
List<ImageCacheInfo> foundImageCacheInfos = db2.query(searchImageCacheInfo);
1495
if(foundImageCacheInfos.size() == 0) {
1496
cacheImage(bucketName, manifestKey, userId, request.isAdministrator());
1497
reply.setSuccess(true);
1502
throw new AccessDeniedException(manifestKey);
1508
throw new NoSuchEntityException(manifestKey);
1511
public FlushCachedImageResponseType FlushCachedImage(FlushCachedImageType request) throws EucalyptusCloudException {
1512
FlushCachedImageResponseType reply = (FlushCachedImageResponseType) request.getReply();
1514
String bucketName = request.getBucket();
1515
String manifestKey = request.getKey();
1517
EntityWrapper<ImageCacheInfo> db = new EntityWrapper<ImageCacheInfo>();
1518
ImageCacheInfo searchImageCacheInfo = new ImageCacheInfo(bucketName, manifestKey);
1519
List<ImageCacheInfo> foundImageCacheInfos = db.query(searchImageCacheInfo);
1521
if(foundImageCacheInfos.size() > 0) {
1522
ImageCacheInfo foundImageCacheInfo = foundImageCacheInfos.get(0);
1523
if(foundImageCacheInfo.getInCache() && !foundImageCacheInfo.getCaching()) {
1524
//check that there are no operations in progress and then flush cache and delete image file
1526
ImageCacheFlusher imageCacheFlusher = new ImageCacheFlusher(bucketName, manifestKey);
1527
imageCacheFlusher.start();
1530
throw new EucalyptusCloudException("not in cache");
1534
throw new NoSuchEntityException(bucketName + manifestKey);
1539
private void flushCachedImage (String bucketName, String objectName) {
1540
WalrusSemaphore semaphore = imageMessenger.getSemaphore(bucketName + "/" + objectName);
1541
while(semaphore.inUse()) {
1543
synchronized (semaphore) {
1546
} catch(InterruptedException ex) {
1550
imageMessenger.removeSemaphore(bucketName + "/" + objectName);
1552
EntityWrapper<ImageCacheInfo> db = new EntityWrapper<ImageCacheInfo>();
1553
ImageCacheInfo searchImageCacheInfo = new ImageCacheInfo(bucketName, objectName);
1554
List<ImageCacheInfo> foundImageCacheInfos = db.query(searchImageCacheInfo);
1556
if(foundImageCacheInfos.size() > 0) {
1557
ImageCacheInfo foundImageCacheInfo = foundImageCacheInfos.get(0);
1558
if(foundImageCacheInfo.getInCache() && !foundImageCacheInfo.getCaching()) {
1559
db.delete(foundImageCacheInfo);
1560
storageManager.deleteObject(bucketName, foundImageCacheInfo.getImageName());
1565
LOG.warn("Cannot find image in cache" + bucketName + "/" + objectName);
1567
} catch(Exception ex) {
1572
private class ImageCacheFlusher extends Thread {
1573
private String bucketName;
1574
private String objectName;
1575
public ImageCacheFlusher(String bucketName, String objectName) {
1576
this.bucketName = bucketName;
1577
this.objectName = objectName;
1581
flushCachedImage(bucketName, objectName);
1585
private class ImageCacher extends Thread {
1587
private String bucketName;
1588
private String manifestKey;
1589
private String decryptedImageKey;
1591
public ImageCacher(String bucketName, String manifestKey, String decryptedImageKey) {
1592
this.bucketName = bucketName;
1593
this.manifestKey = manifestKey;
1594
this.decryptedImageKey = decryptedImageKey;
1597
private long tryToCache(String decryptedImageName, String tarredImageName, String imageName) {
1598
Long unencryptedSize = 0L;
1599
boolean failed = false;
1601
unzipImage(decryptedImageName, tarredImageName);
1602
unencryptedSize = untarImage(tarredImageName, imageName);
1603
Long oldCacheSize = 0L;
1604
EntityWrapper<ImageCacheInfo> db = new EntityWrapper<ImageCacheInfo>();
1605
List<ImageCacheInfo> imageCacheInfos = db.query(new ImageCacheInfo());
1606
for(ImageCacheInfo imageCacheInfo: imageCacheInfos) {
1607
if(imageCacheInfo.getInCache()) {
1608
oldCacheSize += imageCacheInfo.getSize();
1612
if((oldCacheSize + unencryptedSize) > WalrusProperties.IMAGE_CACHE_SIZE) {
1615
} catch(Exception ex) {
1617
//try to evict an entry and try again
1622
storageManager.deleteAbsoluteObject(decryptedImageName);
1623
storageManager.deleteAbsoluteObject(tarredImageName);
1624
} catch (Exception exception) {
1625
LOG.warn(exception, exception);
1629
return unencryptedSize;
1634
//wake up any waiting consumers
1635
String decryptedImageName = storageManager.getObjectPath(bucketName, decryptedImageKey);
1636
String tarredImageName = decryptedImageName.replaceAll("tgz", "tar");
1637
String imageName = tarredImageName.replaceAll(".tar", "");
1638
String imageKey = decryptedImageKey.replaceAll(".tgz", "");
1639
Long unencryptedSize;
1640
while((unencryptedSize = tryToCache(decryptedImageName, tarredImageName, imageName)) < 0) {
1641
EntityWrapper<ImageCacheInfo> db = new EntityWrapper<ImageCacheInfo>();
1642
List<ImageCacheInfo> imageCacheInfos = db.query(new ImageCacheInfo());
1643
ImageCacheInfo imageCacheInfo = null;
1644
if(imageCacheInfos.size() > 1) {
1645
Collections.sort(imageCacheInfos);
1646
imageCacheInfo = imageCacheInfos.get(0);
1650
if(imageCacheInfo != null && imageCacheInfo.getInCache()) {
1651
flushCachedImage(imageCacheInfo.getBucketName(), imageCacheInfo.getManifestName());
1655
storageManager.deleteAbsoluteObject(decryptedImageName);
1656
storageManager.deleteAbsoluteObject(tarredImageName);
1658
EntityWrapper<ImageCacheInfo>db = new EntityWrapper<ImageCacheInfo>();
1659
ImageCacheInfo searchImageCacheInfo = new ImageCacheInfo(bucketName, manifestKey);
1660
List<ImageCacheInfo> foundImageCacheInfos = db.query(searchImageCacheInfo);
1661
if(foundImageCacheInfos.size() > 0) {
1662
ImageCacheInfo foundImageCacheInfo = foundImageCacheInfos.get(0);
1663
foundImageCacheInfo.setImageName(imageKey);
1664
foundImageCacheInfo.setInCache(true);
1665
foundImageCacheInfo.setCaching(false);
1666
foundImageCacheInfo.setSize(unencryptedSize);
1669
WalrusMonitor monitor = imageMessenger.getMonitor(bucketName + "/" + manifestKey);
1670
synchronized (monitor) {
1671
monitor.notifyAll();
1673
imageMessenger.removeMonitor(bucketName + "/" + manifestKey);
1677
LOG.warn("Could not expand image" + decryptedImageName);
1679
} catch (Exception ex) {
1685
private void unzipImage(String decryptedImageName, String tarredImageName) throws Exception {
1686
GZIPInputStream in = new GZIPInputStream(new FileInputStream(new File(decryptedImageName)));
1687
File outFile = new File(tarredImageName);
1688
ReadableByteChannel inChannel = Channels.newChannel(in);
1689
WritableByteChannel outChannel = new FileOutputStream(outFile).getChannel();
1691
ByteBuffer buffer = ByteBuffer.allocate(WalrusQueryDispatcher.DATA_MESSAGE_SIZE);
1692
while (inChannel.read(buffer) != -1) {
1694
outChannel.write(buffer);
1701
private long untarImage(String tarredImageName, String imageName) throws Exception {
1702
TarInputStream in = new TarInputStream(new FileInputStream(new File(tarredImageName)));
1703
File outFile = new File(imageName);
1704
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(outFile));
1706
TarEntry tEntry = in.getNextEntry();
1707
assert(!tEntry.isDirectory());
1709
in.copyEntryContents(out);
1712
return outFile.length();
1715
private void decryptImage(String encryptedImageName, String decyptedImageName, Cipher cipher) {
1717
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(new File(decyptedImageName)));
1718
File inFile = new File(encryptedImageName);
1719
BufferedInputStream in = new BufferedInputStream(new FileInputStream(inFile));
1722
byte[] bytes = new byte[8192];
1724
while((bytesRead = in.read(bytes)) > 0) {
1725
byte[] outBytes = cipher.update(bytes, 0, bytesRead);
1726
out.write(outBytes);
1728
byte[] outBytes = cipher.doFinal();
1729
out.write(outBytes);
1732
} catch(Exception ex) {
1733
ex.printStackTrace();
1737
private void assembleParts(String name, List<String> parts) {
1739
FileChannel out = new FileOutputStream(new File(name)).getChannel();
1740
for (String partName: parts) {
1741
FileChannel in = new FileInputStream(new File(partName)).getChannel();
1742
in.transferTo(0, in.size(), out);
1746
} catch (Exception ex) {
1747
ex.printStackTrace();
1751
private byte[] hexToBytes(String data) {
1753
byte[] results = new byte[data.length() / 2];
1754
for (int i = 0; i < data.length();) {
1755
results[k] = (byte) (Character.digit(data.charAt(i++), 16) << 4);
1756
results[k] += (byte) (Character.digit(data.charAt(i++), 16));
1764
private String bytesToHex(byte[] data) {
1765
StringBuffer buffer = new StringBuffer();
1766
for ( int i = 0; i < data.length; i++ ) {
1767
buffer.append( byteToHex(data[i]) );
1769
return(buffer.toString());
1772
private String byteToHex(byte data) {
1773
StringBuffer hexString = new StringBuffer();
1774
hexString.append(toHex((data>>>4)&0x0F));
1775
hexString.append(toHex(data&0x0F));
1776
return hexString.toString();
1779
private char toHex(int value) {
1780
if ((0 <= value) && (value <= 9 ))
1781
return (char)('0' + value);
1783
return (char)('a' + (value-10));
1786
class Reader extends Thread {
1788
private String bucketName;
1789
private String objectName;
1790
private long objectSize;
1791
private LinkedBlockingQueue<WalrusDataMessage> getQueue;
1792
private long byteRangeStart;
1793
private long byteRangeEnd;
1794
private boolean deleteAfterXfer;
1795
private WalrusSemaphore semaphore;
1797
public Reader(String bucketName, String objectName, long objectSize, LinkedBlockingQueue<WalrusDataMessage> getQueue) {
1798
this.bucketName = bucketName;
1799
this.objectName = objectName;
1800
this.objectSize = objectSize;
1801
this.getQueue = getQueue;
1805
public Reader(String bucketName, String objectName, long objectSize, LinkedBlockingQueue<WalrusDataMessage> getQueue, long byteRangeStart, long byteRangeEnd) {
1806
this.bucketName = bucketName;
1807
this.objectName = objectName;
1808
this.objectSize = objectSize;
1809
this.getQueue = getQueue;
1810
this.byteRangeStart = byteRangeStart;
1811
this.byteRangeEnd = byteRangeEnd;
1814
public Reader(String bucketName, String objectName, long objectSize, LinkedBlockingQueue<WalrusDataMessage> getQueue, boolean deleteAfterXfer, WalrusSemaphore semaphore) {
1815
this(bucketName, objectName, objectSize, getQueue);
1816
this.deleteAfterXfer = deleteAfterXfer;
1817
this.semaphore = semaphore;
1821
byte[] bytes = new byte[WalrusQueryDispatcher.DATA_MESSAGE_SIZE];
1823
long bytesRemaining = objectSize;
1824
long offset = byteRangeStart;
1826
if(byteRangeEnd != 0) {
1827
assert(byteRangeEnd <= objectSize);
1828
assert(byteRangeEnd >= byteRangeStart);
1829
bytesRemaining = byteRangeEnd - byteRangeStart;
1833
getQueue.put(WalrusDataMessage.StartOfData(bytesRemaining));
1835
while (bytesRemaining > 0) {
1836
int bytesRead = storageManager.readObject(bucketName, objectName, bytes, offset);
1837
bytesRemaining -= bytesRead;
1838
getQueue.put(WalrusDataMessage.DataMessage(bytes, bytesRead));
1839
offset += bytesRead;
1841
getQueue.put(WalrusDataMessage.EOF());
1842
} catch (Exception ex) {
1844
//TODO: set error code
1846
if(semaphore != null) {
1847
semaphore.release();
1848
synchronized (semaphore) {
1849
semaphore.notifyAll();
1852
if(deleteAfterXfer) {
1854
storageManager.deleteObject(bucketName, objectName);
1855
} catch(Exception ex) {
1862
public StoreSnapshotResponseType StoreSnapshot(StoreSnapshotType request) throws EucalyptusCloudException {
1863
StoreSnapshotResponseType reply = (StoreSnapshotResponseType) request.getReply();
1864
String volumeId = request.getVolumeId();
1865
String snapshotId = request.getKey();
1867
EntityWrapper<WalrusVolumeInfo> db = new EntityWrapper<WalrusVolumeInfo>();
1868
WalrusVolumeInfo volumeInfo = new WalrusVolumeInfo(volumeId);
1869
List<WalrusVolumeInfo> foundVolumeInfos = db.query(volumeInfo);
1870
WalrusVolumeInfo foundVolumeInfo = null;
1872
if(foundVolumeInfos.size() == 0) {
1873
foundVolumeInfo = volumeInfo;
1874
db.add(foundVolumeInfo);
1876
foundVolumeInfo = foundVolumeInfos.get(0);
1879
WalrusSnapshotInfo snapshotInfo = new WalrusSnapshotInfo(volumeId, snapshotId);
1881
List<WalrusSnapshotInfo> snapshotSet = foundVolumeInfo.getSnapshotSet();
1882
for(WalrusSnapshotInfo snapInfo: snapshotSet) {
1883
if(snapInfo.getSnapshotId().equals(snapshotId)) {
1885
throw new EucalyptusCloudException();
1888
snapshotSet.add(snapshotInfo);
1890
//convert to a PutObject request
1891
PutObjectType putObjectRequest = new PutObjectType();
1892
putObjectRequest.setBucket(request.getBucket());
1893
putObjectRequest.setKey(snapshotId);
1894
putObjectRequest.setRandomKey(request.getRandomKey());
1895
PutObjectResponseType putObjectResponseType = PutObject(putObjectRequest);
1896
reply.setEtag(putObjectResponseType.getEtag());
1897
reply.setLastModified(putObjectResponseType.getLastModified());
1898
reply.setStatusMessage(putObjectResponseType.getStatusMessage());
1902
public GetSnapshotInfoResponseType GetSnapshotInfo(GetSnapshotInfoType request) throws EucalyptusCloudException {
1903
GetSnapshotInfoResponseType reply = (GetSnapshotInfoResponseType)request.getReply();
1904
String snapshotId = request.getKey();
1906
EntityWrapper<WalrusSnapshotInfo> db = new EntityWrapper<WalrusSnapshotInfo>();
1907
WalrusSnapshotInfo snapshotInfo = new WalrusSnapshotInfo(snapshotId);
1908
List<WalrusSnapshotInfo> foundSnapshotInfos = db.query(snapshotInfo);
1910
if(foundSnapshotInfos.size() > 0) {
1911
WalrusSnapshotInfo foundSnapshotInfo = foundSnapshotInfos.get(0);
1912
String volumeId = foundSnapshotInfo.getVolumeId();
1913
WalrusVolumeInfo volumeInfo = new WalrusVolumeInfo(volumeId);
1914
EntityWrapper<WalrusVolumeInfo> db2 = new EntityWrapper<WalrusVolumeInfo>();
1915
List<WalrusVolumeInfo> foundVolumeInfos = db2.query(volumeInfo);
1916
if(foundVolumeInfos.size() > 0) {
1917
WalrusVolumeInfo foundVolumeInfo = foundVolumeInfos.get(0);
1918
List<String> snapshotNames = reply.getSnapshotSet();
1919
snapshotNames.add(volumeId);
1920
for(WalrusSnapshotInfo snapInfo: foundVolumeInfo.getSnapshotSet()) {
1921
snapshotNames.add(snapInfo.getSnapshotId());
1926
throw new EucalyptusCloudException();
1929
throw new EucalyptusCloudException();
1934
public GetSnapshotResponseType GetSnapshot(GetSnapshotType request) throws EucalyptusCloudException {
1935
GetSnapshotResponseType reply = (GetSnapshotResponseType) request.getReply();
1936
String snapshotId = request.getKey();
1941
public RemoveSnapshotResponseType RemoveSnapshot(RemoveSnapshotType request) throws EucalyptusCloudException {
1942
RemoveSnapshotResponseType reply = (RemoveSnapshotResponseType) request.getReply();