4

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

这将如何映射到 的字段并不明显CloudIdentityWithProjectOpenStackIdentityProvider但我尝试了以下和项目名称/用户名/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-UserX-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 对象中。

基于OpenStackIdentityProviderOpenStack.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 IdentityTokenand )的一些成员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。

4

0 回答 0