Openstack.Net SDK无法访问区域服务

使用我们自己的硬件,我们已经安装了包含所有组件的vanilla openstack,但是由于区域问题,我在访问Identity之外的服务时遇到了问题。 使用的管理员帐户和我们创建的管理员终端调用的代码如下所示…

public static void TestAccess(string userName, string password, string projectName, string projectId) { try { Uri baseUrl = new Uri(URL_IDENTITY); CloudIdentityWithProject projectCloudId = new CloudIdentityWithProject(); projectCloudId.Username = userName; projectCloudId.Password = password; projectCloudId.ProjectName = projectName; projectCloudId.ProjectId = new ProjectId(projectId); OpenStackIdentityProvider idProvider = new OpenStackIdentityProvider(baseUrl, projectCloudId); UserAccess userAccess = idProvider.Authenticate(projectCloudId); IEnumerable eps = idProvider.ListEndpoints(userAccess.Token.Id); string reg = idProvider.DefaultRegion; // This is null ServiceCatalog[] scs = userAccess.ServiceCatalog; // Get the list of regions regionList = new List(); foreach (ServiceCatalog sc in scs) { foreach (Endpoint ep in sc.Endpoints) { regionList.Add(ep.Region); // This is 'regionOne' in every case } } // Try stuff... foreach(string region in regionList.Distinct()) { // Get a list of containers CloudFilesProvider cfp = new CloudFilesProvider(projectCloudId, idProvider); // THIS LINE FAILS IEnumerable listOfContainers = cfp.ListContainers(region: region); foreach (Container ctnr in listOfContainers) { Console.WriteLine("Container: {0}", ctnr.Name); } CloudNetworksProvider cnp = new CloudNetworksProvider(identity: null, identityProvider: idProvider); IEnumerable networks = cnp.ListNetworks(identity: null, region: region); foreach (CloudNetwork network in networks) { Console.WriteLine("Network[{0}] name: {1}", networkCount, network.Label); Console.WriteLine("Network[{0}] Id: {1}", networkCount, network.Id); ++networkCount; } Console.WriteLine("{0} networks listed.", networkCount); } } catch(Exception ex) { throw; } } 

代码在调用ListContainers(region:region)时失败并显示错误…’用户无权访问所请求的服务或区域’,就好像我没有指定区域一样,错误只是’没有区域如果提供,该服务不提供与区域无关的端点,并且没有为用户的帐户设置默认区域’

我们目前只访问我们的内部网络,所以区域对我们来说并不重要……

另外值得注意的是,当打电话给…时

 CloudNetwork detail = cnp.ShowNetwork(networkGuid, "regionOne"); 

我可以看到的网络返回错误’项目未找到或不存在。

帮助和建议非常感谢。

我设法简单地扩展了Openstack.Net SDK的function。 下面的代码将其扩展为包含租户/项目操作的各种function……

首先,创建一个NewTenant容器,用于将数据传入和传出Web服务,我将它放在与其他服务器相同的命名空间中……

 using Newtonsoft.Json; namespace net.openstack.Core.Domain { [JsonObject(MemberSerialization.OptIn)] public class NewTenant { ///  /// Gets the ID for the new user. /// The value of this property is not defined. Do not use. ///  [JsonProperty("id", DefaultValueHandling = DefaultValueHandling.Include)] public string Id { get; private set; } [JsonProperty("name")] public string Name { get; private set; } [JsonProperty("description")] public string Description { get; private set; } [JsonProperty("enabled")] public bool Enabled { get; private set; } public NewTenant(string name, string description, bool enabled = true) { Name = name; Description = description; Enabled = enabled; } } } 

现在我们可以创建任何新的Request类来发布数据……

 using System; using Newtonsoft.Json; using net.openstack.Core.Domain; namespace net.openstack.Core.Request { [JsonObject(MemberSerialization.OptIn)] internal class AddTenantRequest { [JsonProperty("tenant")] public NewTenant Tenant { get; private set; } public AddTenantRequest(NewTenant tenant) { if (tenant == null) throw new ArgumentNullException("tenant"); Tenant = tenant; } } } 

现在为请求创建Response对象以帮助检索数据

 using net.openstack.Core.Domain; using Newtonsoft.Json; namespace net.openstack.Core.Response { [JsonObject(MemberSerialization.OptIn)] internal class NewTenantResponse { [JsonProperty("tenant")] public NewTenant NewTenant { get; private set; } } [JsonObject(MemberSerialization.OptIn)] internal class TenantResponse { [JsonProperty("tenant")] public Tenant Tenant { get; private set; } } } 

现在我们可以创建一个inheritance自OpenStackIdentityProvider的类,以及我们想要的Tenant / Project操作的附加function……

 using System; using System.Net; using JSIStudios.SimpleRESTServices.Client; using net.openstack.Core.Domain; using net.openstack.Core.Request; using net.openstack.Core.Response; namespace net.openstack.Core.Providers { public class ExtendedOpenStackIdentityProvider : OpenStackIdentityProvider { public ExtendedOpenStackIdentityProvider(Uri urlBase) : base(urlBase) { } public ExtendedOpenStackIdentityProvider(Uri urlBase, CloudIdentity identity) : base(urlBase, identity) { } public ExtendedOpenStackIdentityProvider(Uri urlBase, JSIStudios.SimpleRESTServices.Client.IRestService restService, net.openstack.Core.Caching.ICache tokenCache) : base(urlBase, restService, tokenCache) { } public ExtendedOpenStackIdentityProvider(Uri urlBase, CloudIdentity identity, JSIStudios.SimpleRESTServices.Client.IRestService restService, net.openstack.Core.Caching.ICache tokenCache) : base(urlBase, identity, restService, tokenCache) { } public NewTenant AddTenant(NewTenant tenant, CloudIdentity identity) { if (tenant == null) throw new ArgumentNullException("tenant"); if (string.IsNullOrEmpty(tenant.Name)) throw new ArgumentException("tenant.Name cannot be null or empty"); if (tenant.Id != null) throw new InvalidOperationException("tenant.Id must be null"); CheckIdentity(identity); var response = ExecuteRESTRequest(identity, new Uri(UrlBase, "/v2.0/tenants"), HttpMethod.POST, new AddTenantRequest(tenant)); if (response == null || response.Data == null) return null; return response.Data.NewTenant; } public Tenant GetTenant(string tenantId, CloudIdentity identity) { if (tenantId == null) throw new ArgumentNullException("tenantId"); CheckIdentity(identity); var urlPath = string.Format("v2.0/tenants/{0}", tenantId); var response = ExecuteRESTRequest(identity, new Uri(UrlBase, urlPath), HttpMethod.GET); if (response == null || response.Data == null) return null; return response.Data.Tenant; } public bool DeleteTenant(string tenantId, CloudIdentity identity) { if (tenantId == null) throw new ArgumentNullException("tenantId"); if (string.IsNullOrEmpty(tenantId)) throw new ArgumentException("tenantId cannot be empty"); CheckIdentity(identity); var urlPath = string.Format("v2.0/tenants/{0}", tenantId); var response = ExecuteRESTRequest(identity, new Uri(UrlBase, urlPath), HttpMethod.DELETE); if (response != null && response.StatusCode == HttpStatusCode.NoContent) return true; return false; } public bool AddTenantUserRole(string tenantId, string userId, string roleId, CloudIdentity identity) { if (tenantId == null) throw new ArgumentNullException("tenantId"); if (string.IsNullOrEmpty(tenantId)) throw new ArgumentException("tenantId cannot be empty"); if (userId == null) throw new ArgumentNullException("userId"); if (string.IsNullOrEmpty(userId)) throw new ArgumentException("userId cannot be empty"); if (roleId == null) throw new ArgumentNullException("roleId"); if (string.IsNullOrEmpty(roleId)) throw new ArgumentException("roleId cannot be empty"); CheckIdentity(identity); var urlPath = string.Format("v2.0/tenants/{0}/users/{1}/roles/OS-KSADM/{2}", tenantId, userId, roleId); var response = ExecuteRESTRequest(identity, new Uri(UrlBase, urlPath), HttpMethod.PUT); if (response != null && response.StatusCode == HttpStatusCode.NoContent) return true; return false; } } } 

我想这个function很快就会出现在GitHub版本中,但如果没有,我希望它有用。