From 02cf554e09585c4a92e97209ffd1db4825136fdb Mon Sep 17 00:00:00 2001 From: Dean Moore Date: Sun, 17 Dec 2017 10:34:10 -0500 Subject: [PATCH] Added support for Wasabi cloud storage --- ArqRestoreCommand.m | 14 +++++++++----- README.markdown | 2 +- Target.h | 1 + Target.m | 10 +++++++++- TargetConnection.m | 2 +- TargetFactory.m | 2 +- arq_restore.m | 1 + 7 files changed, 23 insertions(+), 9 deletions(-) diff --git a/ArqRestoreCommand.m b/ArqRestoreCommand.m index 27ed627..5ac3c3c 100644 --- a/ArqRestoreCommand.m +++ b/ArqRestoreCommand.m @@ -138,18 +138,22 @@ - (BOOL)addTarget:(NSArray *)args error:(NSError **)error { NSString *oAuth2ClientSecret = nil; NSString *oAuth2RedirectURI = nil; - if ([targetType isEqualToString:@"aws"]) { + if ([targetType isEqualToString:@"aws"] || [targetType isEqualToString:@"wasabi"]) { if ([args count] != 5) { SETNSERROR([self errorDomain], ERROR_USAGE, @"invalid arguments"); return NO; } NSString *accessKeyId = [args objectAtIndex:4]; - AWSRegion *usEast1 = [AWSRegion usEast1]; - NSString *urlString = [NSString stringWithFormat:@"https://%@@%@/any_bucket", accessKeyId, [[usEast1 s3EndpointWithSSL:NO] host]]; + NSString *urlString = [NSString stringWithFormat:@"https://%@@s3.wasabisys.com/any_bucket", accessKeyId]; + if ([targetType isEqualToString:@"aws"]) { + AWSRegion *usEast1 = [AWSRegion usEast1]; + urlString = [NSString stringWithFormat:@"https://%@@%@/any_bucket", accessKeyId, [[usEast1 s3EndpointWithSSL:NO] host]]; + } endpoint = [NSURL URLWithString:urlString]; - secret = [self readPasswordWithPrompt:@"enter AWS secret key:" error:error]; + NSString *prompt = [NSString stringWithFormat:@"enter %@ secret key:", [targetType isEqualToString:@"aws"] ? @"AWS" : @"Wasabi"]; + secret = [self readPasswordWithPrompt:prompt error:error]; if (secret == nil) { return NO; } @@ -648,7 +652,7 @@ - (BackupSet *)backupSetForTarget:(Target *)theInitialTarget computerUUID:(NSStr - (NSArray *)expandedTargetListForTarget:(Target *)theTarget error:(NSError **)error { NSArray *targets = nil; - if ([theTarget targetType] == kTargetAWS) { + if ([theTarget targetType] == kTargetAWS || [theTarget targetType] == kTargetWasabi) { targets = [self expandedTargetsForS3Target:theTarget error:error]; } else { targets = [NSArray arrayWithObject:theTarget]; diff --git a/README.markdown b/README.markdown index 41e0b38..a78edbe 100644 --- a/README.markdown +++ b/README.markdown @@ -11,7 +11,7 @@ Use arq_restore to list the computers backed up to your destination, list folder Type `arq_restore` with no arguments to get help. -arq_restore works with Arq backups on AWS or a local filesystem. If you need to restore from backups stored at a different cloud provider, download the backup data to a local filesystem and use arq_restore on that. +arq_restore works with Arq backups on AWS, Wasabi or a local filesystem. If you need to restore from backups stored at a different cloud provider, download the backup data to a local filesystem and use arq_restore on that. ## Prerequisites diff --git a/Target.h b/Target.h index 371aa27..120c880 100644 --- a/Target.h +++ b/Target.h @@ -41,6 +41,7 @@ enum TargetType { kTargetAWS = 0, + kTargetWasabi = 6, kTargetLocal = 12 }; typedef int TargetType; diff --git a/Target.m b/Target.m index e953a07..f304107 100644 --- a/Target.m +++ b/Target.m @@ -254,7 +254,11 @@ - (BOOL)deleteOAuth2ClientSecret:(NSError **)error { - (DictNode *)toPlist { DictNode *ret = [[[DictNode alloc] init] autorelease]; - [ret putString:@"s3" forKey:@"targetType"]; // Used by TargetFactory + if (targetType == kTargetWasabi) { + [ret putString:@"wasabi" forKey:@"targetType"]; // Used by TargetFactory + } else { + [ret putString:@"s3" forKey:@"targetType"]; // Used by TargetFactory + } [ret putString:nickname forKey:@"nickname"]; [ret putString:uuid forKey:@"uuid"]; [ret putString:[endpoint absoluteString] forKey:@"endpointDescription"]; @@ -346,6 +350,10 @@ - (TargetType)targetTypeForEndpoint { if ([[[self endpoint] scheme] isEqualToString:@"file"]) { return kTargetLocal; } + NSString *host = [[self endpoint] host]; + if ([host hasSuffix:@"wasabisys.com"]) { + return kTargetWasabi; + } return kTargetAWS; } diff --git a/TargetConnection.m b/TargetConnection.m index c199a75..df26b7d 100644 --- a/TargetConnection.m +++ b/TargetConnection.m @@ -519,7 +519,7 @@ - (RemoteFS *)newRemoteFS:(NSError **)error { return nil; } - } else if (targetType == kTargetAWS) { + } else if (targetType == kTargetAWS || targetType == kTargetWasabi) { AWSRegion *region = [AWSRegion regionWithS3Endpoint:[target endpoint]]; if (region == nil) { region = [AWSRegion usEast1]; diff --git a/TargetFactory.m b/TargetFactory.m index 397cc21..d514337 100644 --- a/TargetFactory.m +++ b/TargetFactory.m @@ -242,7 +242,7 @@ - (Target *)targetWithPlistPath:(NSString *)thePath error:(NSError **)error { return nil; } NSString *targetType = [[plist stringNodeForKey:@"targetType"] stringValue]; - if ([targetType isEqualToString:@"s3"]) { + if ([targetType isEqualToString:@"s3"] || [targetType isEqualToString:@"wasabi"]) { return [[[Target alloc] initWithPlist:plist] autorelease]; } SETNSERROR([self errorDomain], -1, @"unknown target type '%@'", targetType); diff --git a/arq_restore.m b/arq_restore.m index ce92434..ea14407 100644 --- a/arq_restore.m +++ b/arq_restore.m @@ -41,6 +41,7 @@ static void printUsage(const char *exeName) { fprintf(stderr, "Usage:\n"); fprintf(stderr, "\t%s [-l loglevel] listtargets\n", exeName); fprintf(stderr, "\t%s [-l loglevel] addtarget aws \n", exeName); + fprintf(stderr, "\t%s [-l loglevel] addtarget wasabi \n", exeName); fprintf(stderr, "\t%s [-l loglevel] addtarget local \n", exeName); fprintf(stderr, "\t%s [-l loglevel] deletetarget \n", exeName); fprintf(stderr, "\n");