SoftLayer 对象存储基于OpenStack Swift对象存储。
SoftLayer 在 Python、Ruby、Java 和 PHP 中为他们的对象存储提供 SDK,但不在 .NET 中。在为 OpenStack 搜索 .NET SDK 时,我遇到了OpenStack.NET。
基于这个问题,OpenStack.NET 默认设计为与 Rackspace 一起使用,但可以使用CloudIdentityWithProject
和与其他 OpenStack 提供程序一起使用OpenStackIdentityProvider
。
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。
根据SoftLayer的这篇文章和 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 对象中。
基于OpenStackIdentityProvider
OpenStack.NET 中的类,我将自己的类组合在一起,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
因为(like IdentityToken
and )的一些成员Endpoint
无法设置它们的字段(对象只有一个默认构造函数并且只有只读成员),所以我必须UserAccess
通过反序列化一些与返回的格式类似的临时 JSON 来创建对象通过 V2 API。
这有效,即我现在可以这样连接:
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。