2024-02-28 15:45:30 +01:00
|
|
|
// Copyright (C) 2024, The Duplicati Team
|
|
|
|
|
// https://duplicati.com, hello@duplicati.com
|
2014-07-06 08:52:43 -04:00
|
|
|
//
|
2024-02-28 15:45:30 +01:00
|
|
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
|
// copy of this software and associated documentation files (the "Software"),
|
|
|
|
|
// to deal in the Software without restriction, including without limitation
|
|
|
|
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
|
|
// and/or sell copies of the Software, and to permit persons to whom the
|
|
|
|
|
// Software is furnished to do so, subject to the following conditions:
|
2014-07-06 08:52:43 -04:00
|
|
|
//
|
2024-02-28 15:45:30 +01:00
|
|
|
// The above copyright notice and this permission notice shall be included in
|
|
|
|
|
// all copies or substantial portions of the Software.
|
2014-07-06 08:52:43 -04:00
|
|
|
//
|
2024-02-28 15:45:30 +01:00
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
|
|
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
|
|
|
// DEALINGS IN THE SOFTWARE.
|
2014-07-06 08:52:43 -04:00
|
|
|
|
2019-02-22 21:58:40 -06:00
|
|
|
using Duplicati.Library.Interface;
|
2014-07-06 08:52:43 -04:00
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.IO;
|
2019-04-28 11:50:28 -07:00
|
|
|
using System.Threading;
|
|
|
|
|
using System.Threading.Tasks;
|
2014-07-06 08:52:43 -04:00
|
|
|
|
|
|
|
|
namespace Duplicati.Library.Backend.AzureBlob
|
|
|
|
|
{
|
2019-04-28 11:50:28 -07:00
|
|
|
// ReSharper disable once UnusedMember.Global
|
|
|
|
|
// This class is instantiated dynamically in the BackendLoader.
|
2014-07-06 08:52:43 -04:00
|
|
|
public class AzureBlobBackend : IStreamingBackend
|
|
|
|
|
{
|
|
|
|
|
private readonly AzureBlobWrapper _azureBlob;
|
|
|
|
|
|
2019-04-28 11:51:31 -07:00
|
|
|
// ReSharper disable once UnusedMember.Global
|
|
|
|
|
// This constructor is needed by the BackendLoader.
|
2014-07-06 08:52:43 -04:00
|
|
|
public AzureBlobBackend()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-28 11:51:31 -07:00
|
|
|
// ReSharper disable once UnusedMember.Global
|
|
|
|
|
// This constructor is needed by the BackendLoader.
|
2014-07-06 08:52:43 -04:00
|
|
|
public AzureBlobBackend(string url, Dictionary<string, string> options)
|
|
|
|
|
{
|
2014-08-02 18:36:35 -04:00
|
|
|
var uri = new Utility.Uri(url);
|
|
|
|
|
uri.RequireHost();
|
|
|
|
|
|
|
|
|
|
string storageAccountName = null;
|
|
|
|
|
string accessKey = null;
|
2021-05-15 21:22:50 +10:00
|
|
|
string sasToken = null;
|
2014-08-02 18:36:35 -04:00
|
|
|
string containerName = uri.Host.ToLowerInvariant();
|
|
|
|
|
|
|
|
|
|
if (options.ContainsKey("auth-username"))
|
|
|
|
|
storageAccountName = options["auth-username"];
|
|
|
|
|
if (options.ContainsKey("auth-password"))
|
2021-05-15 21:22:50 +10:00
|
|
|
accessKey = options["auth-password"];
|
|
|
|
|
|
|
|
|
|
if (options.ContainsKey("azure_account_name"))
|
|
|
|
|
storageAccountName = options["azure_account_name"];
|
2021-05-15 14:06:39 -07:00
|
|
|
if (options.ContainsKey("azure-account-name"))
|
2021-05-15 21:03:26 +10:00
|
|
|
storageAccountName = options["azure-account-name"];
|
|
|
|
|
|
|
|
|
|
if (options.ContainsKey("azure_access_key"))
|
2021-05-15 21:22:50 +10:00
|
|
|
accessKey = options["azure_access_key"];
|
2021-05-15 14:06:39 -07:00
|
|
|
if (options.ContainsKey("azure-access-key"))
|
2021-05-15 21:03:26 +10:00
|
|
|
accessKey = options["azure-access-key"];
|
|
|
|
|
|
2021-05-15 21:22:50 +10:00
|
|
|
if (options.ContainsKey("azure-access-sas-token"))
|
|
|
|
|
sasToken = options["azure-access-sas-token"];
|
2021-05-29 12:20:30 +02:00
|
|
|
|
2014-08-02 18:36:35 -04:00
|
|
|
if (!string.IsNullOrEmpty(uri.Username))
|
|
|
|
|
storageAccountName = uri.Username;
|
|
|
|
|
if (!string.IsNullOrEmpty(uri.Password))
|
|
|
|
|
accessKey = uri.Password;
|
|
|
|
|
|
|
|
|
|
if (string.IsNullOrWhiteSpace(storageAccountName))
|
2014-07-06 08:52:43 -04:00
|
|
|
{
|
2018-03-12 14:07:11 +01:00
|
|
|
throw new UserInformationException(Strings.AzureBlobBackend.NoStorageAccountName, "AzureNoAccountName");
|
2014-07-06 08:52:43 -04:00
|
|
|
}
|
2021-05-15 21:22:50 +10:00
|
|
|
if (string.IsNullOrWhiteSpace(accessKey) && string.IsNullOrWhiteSpace(sasToken))
|
2014-07-06 08:52:43 -04:00
|
|
|
{
|
2021-05-15 21:22:50 +10:00
|
|
|
throw new UserInformationException(Strings.AzureBlobBackend.NoAccessKeyOrSasToken, "AzureNoAccessKeyOrSasToken");
|
2014-07-06 08:52:43 -04:00
|
|
|
}
|
|
|
|
|
|
2021-05-15 21:22:50 +10:00
|
|
|
|
|
|
|
|
_azureBlob = new AzureBlobWrapper(storageAccountName, accessKey, sasToken, containerName);
|
2014-07-06 08:52:43 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string DisplayName
|
|
|
|
|
{
|
|
|
|
|
get { return Strings.AzureBlobBackend.DisplayName; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string ProtocolKey
|
|
|
|
|
{
|
|
|
|
|
get { return "azure"; }
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-25 23:17:45 -06:00
|
|
|
public IEnumerable<IFileEntry> List()
|
2014-07-06 08:52:43 -04:00
|
|
|
{
|
|
|
|
|
return _azureBlob.ListContainerEntries();
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-12 11:30:08 -07:00
|
|
|
public async Task PutAsync(string remotename, string localname, CancellationToken cancelToken)
|
2014-07-06 08:52:43 -04:00
|
|
|
{
|
|
|
|
|
using (var fs = File.Open(localname,
|
|
|
|
|
FileMode.Open, FileAccess.Read, FileShare.Read))
|
|
|
|
|
{
|
2021-06-12 11:30:08 -07:00
|
|
|
await PutAsync(remotename, fs, cancelToken);
|
2014-07-06 08:52:43 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-17 18:20:14 -05:00
|
|
|
public async Task PutAsync(string remotename, Stream input, CancellationToken cancelToken)
|
2014-07-06 08:52:43 -04:00
|
|
|
{
|
2019-02-23 09:10:56 -06:00
|
|
|
await _azureBlob.AddFileStream(remotename, input, cancelToken);
|
2014-07-06 08:52:43 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Get(string remotename, string localname)
|
|
|
|
|
{
|
|
|
|
|
using (var fs = File.Open(localname,
|
|
|
|
|
FileMode.Create, FileAccess.Write,
|
|
|
|
|
FileShare.None))
|
|
|
|
|
{
|
|
|
|
|
Get(remotename, fs);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Get(string remotename, Stream output)
|
|
|
|
|
{
|
|
|
|
|
_azureBlob.GetFileStream(remotename, output);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Delete(string remotename)
|
|
|
|
|
{
|
|
|
|
|
_azureBlob.DeleteObject(remotename);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public IList<ICommandLineArgument> SupportedCommands
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return new List<ICommandLineArgument>(new ICommandLineArgument[] {
|
2021-02-15 15:53:13 +00:00
|
|
|
new CommandLineArgument("azure_account_name",
|
|
|
|
|
CommandLineArgument.ArgumentType.String,
|
|
|
|
|
Strings.AzureBlobBackend.StorageAccountNameDescriptionShort,
|
2021-02-16 10:41:55 +00:00
|
|
|
Strings.AzureBlobBackend.StorageAccountNameDescriptionLong,
|
2021-02-16 17:10:02 +00:00
|
|
|
null, null, null, "This is deprecated, use azure-account-name instead"),
|
2021-02-15 15:53:13 +00:00
|
|
|
new CommandLineArgument("azure_access_key",
|
|
|
|
|
CommandLineArgument.ArgumentType.Password,
|
|
|
|
|
Strings.AzureBlobBackend.AccessKeyDescriptionShort,
|
2021-02-16 10:41:55 +00:00
|
|
|
Strings.AzureBlobBackend.AccessKeyDescriptionLong,
|
2021-02-16 17:10:02 +00:00
|
|
|
null, null, null, "This is deprecated, use azure-access-key instead"),
|
2021-02-15 15:53:13 +00:00
|
|
|
new CommandLineArgument("azure_blob_container_name",
|
|
|
|
|
CommandLineArgument.ArgumentType.String,
|
|
|
|
|
Strings.AzureBlobBackend.ContainerNameDescriptionShort,
|
2021-02-16 10:41:55 +00:00
|
|
|
Strings.AzureBlobBackend.ContainerNameDescriptionLong,
|
2021-02-16 17:10:02 +00:00
|
|
|
null, null, null, "This is deprecated, use azure-blob-container-name instead"),
|
2021-02-15 15:53:13 +00:00
|
|
|
new CommandLineArgument("azure-account-name",
|
|
|
|
|
CommandLineArgument.ArgumentType.String,
|
|
|
|
|
Strings.AzureBlobBackend.StorageAccountNameDescriptionShort,
|
|
|
|
|
Strings.AzureBlobBackend.StorageAccountNameDescriptionLong),
|
|
|
|
|
new CommandLineArgument("azure-access-key",
|
|
|
|
|
CommandLineArgument.ArgumentType.Password,
|
|
|
|
|
Strings.AzureBlobBackend.AccessKeyDescriptionShort,
|
|
|
|
|
Strings.AzureBlobBackend.AccessKeyDescriptionLong),
|
2021-05-15 21:22:50 +10:00
|
|
|
new CommandLineArgument("azure-access-sas-token",
|
|
|
|
|
CommandLineArgument.ArgumentType.Password,
|
|
|
|
|
Strings.AzureBlobBackend.SasTokenDescriptionShort,
|
|
|
|
|
Strings.AzureBlobBackend.SasTokenDescriptionLong),
|
2021-02-15 15:53:13 +00:00
|
|
|
new CommandLineArgument("azure-blob-container-name",
|
|
|
|
|
CommandLineArgument.ArgumentType.String,
|
|
|
|
|
Strings.AzureBlobBackend.ContainerNameDescriptionShort,
|
|
|
|
|
Strings.AzureBlobBackend.ContainerNameDescriptionLong),
|
|
|
|
|
new CommandLineArgument("auth-password",
|
|
|
|
|
CommandLineArgument.ArgumentType.Password,
|
|
|
|
|
Strings.AzureBlobBackend.AuthPasswordDescriptionShort,
|
2014-08-02 18:36:35 -04:00
|
|
|
Strings.AzureBlobBackend.AuthPasswordDescriptionLong),
|
2021-02-15 15:53:13 +00:00
|
|
|
new CommandLineArgument("auth-username",
|
|
|
|
|
CommandLineArgument.ArgumentType.String,
|
|
|
|
|
Strings.AzureBlobBackend.AuthUsernameDescriptionShort,
|
2014-08-02 18:36:35 -04:00
|
|
|
Strings.AzureBlobBackend.AuthUsernameDescriptionLong)
|
2014-07-06 08:52:43 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string Description
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return Strings.AzureBlobBackend.Description_v2;
|
|
|
|
|
}
|
2019-04-28 11:50:28 -07:00
|
|
|
}
|
|
|
|
|
|
2018-02-26 11:37:10 +01:00
|
|
|
public string[] DNSName
|
2018-02-21 22:38:01 +01:00
|
|
|
{
|
2018-02-26 11:37:10 +01:00
|
|
|
get { return _azureBlob.DnsNames; }
|
2019-04-28 11:50:28 -07:00
|
|
|
}
|
|
|
|
|
|
2014-07-06 08:52:43 -04:00
|
|
|
public void Test()
|
|
|
|
|
{
|
2017-09-25 23:17:45 -06:00
|
|
|
this.TestList();
|
2014-07-06 08:52:43 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void CreateFolder()
|
|
|
|
|
{
|
|
|
|
|
_azureBlob.AddContainer();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Dispose()
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|