Added support for multi-region catalog

OpenStack wrapper will read the 'region_name' from config, and use
the correct endpoint matching this region

Change-Id: I01049f3bed227eb1e11f9a1f7d338177e95aef34
This commit is contained in:
Corentin Ardeois 2016-10-25 12:38:29 +02:00
parent f137472a44
commit 0a4fb9f8b9
4 changed files with 64 additions and 17 deletions

View File

@ -83,10 +83,13 @@ export default class OpenStack {
* @private * @private
*/ */
_getComponentConfigFor(name) { _getComponentConfigFor(name) {
const config = this.getConfig();
return this._token return this._token
.then((token) => this._keystone.then((keystone) => keystone.catalogList(token))) .then((token) => this._keystone.then((keystone) => keystone.catalogList(token)))
.then((catalog) => catalog.find((entry) => entry.name === name)) .then((catalog) => catalog.find((entry) => entry.name === name))
.then((entry) => entry.endpoints.find((endpoint) => endpoint.interface === 'public')); .then((entry) => entry.endpoints.find((endpoint) => {
return endpoint.region === config.region_name && endpoint.interface === 'public';
}));
} }
} }

View File

@ -253,6 +253,27 @@ const catalogListData = [
region: "RegionOne", region: "RegionOne",
interface: "admin", interface: "admin",
id: "bd8db1bafe41489bbbc45641e525ee7d" id: "bd8db1bafe41489bbbc45641e525ee7d"
},
{
region_id: "RegionTwo",
url: "http://192.168.99.100:9696/",
region: "RegionTwo",
interface: "public",
id: "7033fa4ebed74e3fa51753162150a1f2"
},
{
region_id: "RegionTwo",
url: "http://192.168.99.100:9696/",
region: "RegionOne",
interface: "RegionTwo",
id: "7aa942d402a34d4c90454b9d84285855"
},
{
region_id: "RegionTwo",
url: "http://192.168.99.100:9696/",
region: "RegionTwo",
interface: "admin",
id: "bd8db1bafe41489bbbc45641e525ee7d"
} }
], ],
type: "network", type: "network",

View File

@ -22,16 +22,21 @@
/** /**
* Mock cloud configuration that matches our test data below. This is not a full clouds.yaml * Mock cloud configuration that matches our test data below. This is not a full clouds.yaml
* format, rather just the subsection pointing to a particular cloud. * format, rather just the subsection pointing to a particular cloud.
* @param {String} regionName A region name to use
* @returns {{}} a cloud config object.
*/ */
const cloudConfig = { function cloudConfig(regionName = 'RegionOne') {
region_name: 'Region1', return {
region_name: regionName,
auth: { auth: {
username: 'user', username: 'user',
password: 'pass', password: 'pass',
project_name: 'js-openstack-lib', project_name: 'js-openstack-lib',
auth_url: 'http://192.168.99.99/' auth_url: 'http://192.168.99.99/'
} }
}; };
}
export { export {
cloudConfig as config, cloudConfig as config,
}; };

View File

@ -11,7 +11,7 @@ describe("Simple test", () => {
afterEach(fetchMock.restore); afterEach(fetchMock.restore);
it("should export a class", () => { it("should export a class", () => {
let t = new OpenStack(openStackMockData.config); let t = new OpenStack(openStackMockData.config());
expect(t).toBeDefined(); expect(t).toBeDefined();
}); });
@ -25,14 +25,14 @@ describe("Simple test", () => {
}); });
it("getConfig should returns the config", () => { it("getConfig should returns the config", () => {
let openstack = new OpenStack(openStackMockData.config); let openstack = new OpenStack(openStackMockData.config());
let config = openstack.getConfig(); let config = openstack.getConfig();
expect(config.region_name).toEqual('Region1'); expect(config.region_name).toEqual('RegionOne');
}); });
describe('networkList', () => { describe('networkList', () => {
it('should fetch networkList from neutron', (done) => { it('should fetch networkList from neutron', (done) => {
const openstack = new OpenStack(openStackMockData.config); const openstack = new OpenStack(openStackMockData.config());
const neutron = mockNeutron(openstack); const neutron = mockNeutron(openstack);
const networksData = neutronMockData.networkList('token').response.networks; const networksData = neutronMockData.networkList('token').response.networks;
@ -50,7 +50,7 @@ describe("Simple test", () => {
describe('_neutron', () => { describe('_neutron', () => {
it('creates Neutron instance with the correct endpoint', (done) => { it('creates Neutron instance with the correct endpoint', (done) => {
const token = 'test_token'; const token = 'test_token';
const openstack = new OpenStack(openStackMockData.config); const openstack = new OpenStack(openStackMockData.config());
const keystone = mockKeystone(openstack); const keystone = mockKeystone(openstack);
const catalogData = keystoneMockData.catalogList(token).response.catalog; const catalogData = keystoneMockData.catalogList(token).response.catalog;
@ -67,8 +67,26 @@ describe("Simple test", () => {
.catch((error) => done.fail(error)); .catch((error) => done.fail(error));
}); });
it('creates Neutron instance for the correct endpoint', (done) => {
const token = 'test_token';
const openstack = new OpenStack(openStackMockData.config('RegionTwo'));
const keystone = mockKeystone(openstack);
const catalogData = keystoneMockData.catalogList(token).response.catalog;
spyOn(keystone, 'tokenIssue').and.returnValue(Promise.resolve(token));
spyOn(keystone, 'catalogList').and.returnValue(Promise.resolve(catalogData));
openstack._neutron
.then((neutron) => {
expect(neutron).toEqual(jasmine.any(Neutron));
expect(neutron.endpointUrl).toEqual('http://192.168.99.100:9696/');
done();
})
.catch((error) => done.fail(error));
});
it('should cache Neutron instance and Keystone token', (done) => { it('should cache Neutron instance and Keystone token', (done) => {
const openstack = new OpenStack(openStackMockData.config); const openstack = new OpenStack(openStackMockData.config());
const tokenIssueMock = keystoneMockData.tokenIssue(); const tokenIssueMock = keystoneMockData.tokenIssue();
const catalogListMock = keystoneMockData.catalogList('test_token'); const catalogListMock = keystoneMockData.catalogList('test_token');
@ -95,7 +113,7 @@ describe("Simple test", () => {
describe('_token', () => { describe('_token', () => {
it('should fetch the token and cache it', (done) => { it('should fetch the token and cache it', (done) => {
const openstack = new OpenStack(openStackMockData.config); const openstack = new OpenStack(openStackMockData.config());
const keystone = mockKeystone(openstack); const keystone = mockKeystone(openstack);
spyOn(keystone, 'tokenIssue').and.returnValue(Promise.resolve('test_token')); spyOn(keystone, 'tokenIssue').and.returnValue(Promise.resolve('test_token'));