SoftLayer Object Storage基于OpenStack Swift对象库。
SoftLayer为Python,Ruby,Java和PHP中的对象存储提供SDK,但不提供.NET。在为OpenStack搜索.NET SDK时,我遇到了OpenStack.NET。
基于this question OpenStack.NET默认设计用于Rackspace,但可以使用CloudIdentityWithProject
和OpenStackIdentityProvider
与其他OpenStack提供商合作。
SoftLayer提供以下有关连接其对象存储的信息:
Authentication Endpoint
Public: https://mel01.objectstorage.softlayer.net/auth/v1.0/
Private: https://mel01.objectstorage.service.networklayer.com/auth/v1.0/
Username:
SLOS123456-1:email@example.com
API Key (Password):
1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef
这不会显示如何映射到CloudIdentityWithProject
和OpenStackIdentityProvider
的字段,但我尝试了以下以及项目名称/用户名/ uri的其他一些组合:
var cloudIdentity = new CloudIdentityWithProject()
{
ProjectName = "SLOS123456-1",
Username = "email@example.com",
Password = "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
};
var identityProvider = new OpenStackIdentityProvider(
new Uri("https://mel01.objectstorage.softlayer.net/auth/v1.0/"),
cloudIdentity);
var token = identityProvider.GetToken(null);
但是,在所有情况下,我都收到以下错误:
Unable to authenticate user and retrieve authorized service endpoints
基于查看SoftLayer的其他语言库和OpenStack.NET的源代码,看起来SoftLayer的对象存储使用V1 auth,而OpenStack.NET使用V2 auth。
基于this article from SoftLayer和this article from SwiftStack,V1 auth使用/auth/v1.0/
路径(类似于SoftLayer提供的路径),X-Auth-User
和X-Auth-Key
标头为参数,以及包含在标题中的响应,如下所示:
X-Auth-Token-Expires = 83436
X-Auth-Token = AUTH_tk1234567890abcdef1234567890abcdef
X-Storage-Token = AUTH_tk1234567890abcdef1234567890abcdef
X-Storage-Url = https://mel01.objectstorage.softlayer.net/v1/AUTH_12345678-1234-1234-1234-1234567890ab
X-Trans-Id = txbc1234567890abcdef123-1234567890
Connection = keep-alive
Content-Length = 1300
Content-Type = text/html; charset=UTF-8
Date = Wed, 14 Oct 2015 01:19:45 GMT
V2 auth(identity API V2.0)使用/v2.0/tokens
路径,而消息体中的JSON对象中包含请求和响应。
基于OpenStack.NET中的OpenStackIdentityProvider
类,我一起攻击了我自己的SoftLayerOpenStackIdentityProvider
:
using JSIStudios.SimpleRESTServices.Client;
using net.openstack.Core.Domain;
using net.openstack.Providers.Rackspace;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using OpenStack.Authentication;
using System;
using System.Linq;
using System.Collections.Generic;
namespace OpenStackTest1
{
public class SoftLayerOpenStackIdentityProvider : CloudIdentityProvider
{
public SoftLayerOpenStackIdentityProvider(
Uri urlBase, CloudIdentity defaultIdentity)
: base(defaultIdentity, null, null, urlBase)
{
if (urlBase == null)
throw new ArgumentNullException("urlBase");
}
public override UserAccess GetUserAccess(
CloudIdentity identity, bool forceCacheRefresh = false)
{
identity = identity ?? DefaultIdentity;
Func<UserAccess> refreshCallback =
() =>
{
// Set up request headers.
Dictionary<string, string> headers =
new Dictionary<string, string>();
headers["X-Auth-User"] = identity.Username;
headers["X-Auth-Key"] = identity.APIKey;
// Make the request.
JObject requestBody = null;
var response = ExecuteRESTRequest<JObject>(
identity,
UrlBase,
HttpMethod.GET,
requestBody,
headers: headers,
isTokenRequest: true);
if (response == null || response.Data == null)
return null;
// Get response headers.
string authToken = response.Headers.Single(
h => h.Key == "X-Auth-Token").Value;
string storageUrl = response.Headers.Single(
h => h.Key == "X-Storage-Url").Value;
string tokenExpires = response.Headers.Single(
h => h.Key == "X-Auth-Token-Expires").Value;
// Convert expiry from seconds to a date.
int tokenExpiresSeconds = Int32.Parse(tokenExpires);
DateTimeOffset tokenExpiresDate =
DateTimeOffset.UtcNow.AddSeconds(tokenExpiresSeconds);
// Create UserAccess via JSON deseralization.
UserAccess access = JsonConvert.DeserializeObject<UserAccess>(
String.Format(
"{{ " +
" token: {{ id: '{0}', expires: '{1}' }}, " +
" serviceCatalog: " +
" [ " +
" {{ " +
" endpoints: [ {{ publicUrl: '{2}' }} ], " +
" type: 'object-store', " +
" name: 'swift' " +
" }} " +
" ], " +
" user: {{ }} " +
"}}",
authToken,
tokenExpiresDate,
storageUrl));
if (access == null || access.Token == null)
return null;
return access;
};
string key = string.Format("{0}:{1}", UrlBase, identity.Username);
var userAccess = TokenCache.Get(key, refreshCallback, forceCacheRefresh);
return userAccess;
}
protected override string LookupServiceTypeKey(IServiceType serviceType)
{
return serviceType.Type;
}
}
}
因为UserAccess
的某些成员(如IdentityToken
和Endpoint
)无法设置其字段(对象只有默认构造函数且只有只读成员) ,我必须通过以V2 API返回的类似格式反序列化一些临时JSON来创建UserAccess
对象。
这有效,即我现在可以像这样连接:
var cloudIdentity = new CloudIdentity()
{
Username = "SLOS123456-1:email@example.com",
APIKey = "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
};
var identityProvider = new SoftLayerOpenStackIdentityProvider(
new Uri("https://mel01.objectstorage.softlayer.net/auth/v1.0/"),
cloudIdentity);
var token = identityProvider.GetToken(null);
然后像这样访问文件等:
var cloudFilesProvider = new CloudFilesProvider(identityProvider);
var containers = cloudFilesProvider.ListContainers();
var stream = new MemoryStream();
cloudFilesProvider.GetObject("testcontainer", "testfile.dat", stream);
但是,有没有比这更好的方法来使用.NET的SoftLayer对象存储?
我简要地查看了OpenStack SDK for .NET(与OpenStack.NET不同的库),但它似乎也基于V2 auth。