Upgrade to keystone v3
Implements: blueprint keystone-v3 Closes-Bug: #1671479 Change-Id: Ic168c652dceb93e820f053e406e992c7dc161573
This commit is contained in:
parent
76e5d143df
commit
89e063f932
@ -4,12 +4,12 @@ window.tripleOUiConfig = {
|
||||
// A valid Keystone service URL is required. The other endpoints
|
||||
// will then be obtained automatically from the Keystone catalog.
|
||||
//
|
||||
// 'keystone': 'http://192.0.2.1:5000/v2.0',
|
||||
// 'keystone': 'http://192.0.2.1:5000/v3',
|
||||
//
|
||||
// 'heat': 'http://192.0.2.1:8004/v1/%(tenant_id)s',
|
||||
// 'heat': 'http://192.0.2.1:8004/v1/%(project_id)s',
|
||||
// 'ironic': 'http://192.0.2.1:6385',
|
||||
// 'mistral': 'http://192.0.2.1:8989/v2',
|
||||
// 'swift': 'http://192.0.2.1:8080/v1/AUTH_%(tenant_id)s',
|
||||
// 'swift': 'http://192.0.2.1:8080/v1/AUTH_%(project_id)s',
|
||||
// 'zaqar-websocket': 'ws://192.0.2.1:9000',
|
||||
|
||||
// Default websocket queue name
|
||||
|
5
releasenotes/notes/keystone-v3-17b6b160a0a97965.yaml
Normal file
5
releasenotes/notes/keystone-v3-17b6b160a0a97965.yaml
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
fixes:
|
||||
- |
|
||||
Fixes `bug 1671479 <https://launchpad.net/bugs/1671479>`__
|
||||
Upgrade the UI to use keystone v3
|
@ -6,20 +6,19 @@ import store from '../../js/store';
|
||||
describe('utility functions', () => {
|
||||
const appState = {
|
||||
login: new InitialLoginState({
|
||||
keystoneAccess: Map({
|
||||
token: Map({
|
||||
id: 123456,
|
||||
tenant: Map({
|
||||
project: Map({
|
||||
id: 778899
|
||||
})
|
||||
}),
|
||||
serviceCatalog: List([
|
||||
catalog: List([
|
||||
Map({
|
||||
name: 'nova',
|
||||
endpoints: List([
|
||||
Map({
|
||||
adminURL: 'http://someNovaAdminUrl',
|
||||
publicURL: 'http://someNovaPublicUrl'
|
||||
id: '1',
|
||||
interface: 'public',
|
||||
url: 'http://someNovaPublicUrl'
|
||||
})
|
||||
])
|
||||
}),
|
||||
@ -27,7 +26,9 @@ describe('utility functions', () => {
|
||||
name: 'fooservice',
|
||||
endpoints: List([
|
||||
Map({
|
||||
publicURL: 'http://IGNOREDFooPublicUrl'
|
||||
id: '1',
|
||||
interface: 'public',
|
||||
url: 'http://someNovaPublicUrl'
|
||||
})
|
||||
])
|
||||
}),
|
||||
@ -35,7 +36,9 @@ describe('utility functions', () => {
|
||||
name: 'macroservice',
|
||||
endpoints: List([
|
||||
Map({
|
||||
publicURL: 'http://MacroPublicUrl/v1/Foo_%(tenant_id)s'
|
||||
id: '1',
|
||||
interface: 'public',
|
||||
url: 'http://MacroPublicUrl/v1/Foo_%(project_id)s'
|
||||
})
|
||||
])
|
||||
})
|
||||
@ -68,7 +71,7 @@ describe('utility functions', () => {
|
||||
).toEqual('http://FooPublicURL');
|
||||
});
|
||||
|
||||
it('expands urls containing the keystone tenant macro', () => {
|
||||
it('expands urls containing the keystone project macro', () => {
|
||||
expect(getServiceUrl('macroservice')).toEqual('http://MacroPublicUrl/v1/Foo_778899');
|
||||
});
|
||||
});
|
||||
|
@ -12,11 +12,12 @@ export default {
|
||||
authenticateUserViaToken(keystoneAuthTokenId, nextPath) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch(this.userAuthStarted());
|
||||
KeystoneApiService.authenticateUserViaToken(keystoneAuthTokenId).then((response) => {
|
||||
cookie.save('keystoneAuthTokenId',
|
||||
response.access.token.id,
|
||||
{ path: '/' });
|
||||
dispatch(this.userAuthSuccess(response.access));
|
||||
KeystoneApiService.authenticateUserViaToken(keystoneAuthTokenId).then((result) => {
|
||||
const tokenId = result.request.getResponseHeader('X-Subject-Token');
|
||||
let response = result.response;
|
||||
response.token.id = tokenId;
|
||||
cookie.save('keystoneAuthTokenId', tokenId, { path: '/' });
|
||||
dispatch(this.userAuthSuccess(response.token));
|
||||
ZaqarWebSocketService.init(getState, dispatch);
|
||||
browserHistory.push(nextPath);
|
||||
}).catch((error) => {
|
||||
@ -32,11 +33,12 @@ export default {
|
||||
authenticateUser(formData, formFields, nextPath) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch(this.userAuthStarted());
|
||||
KeystoneApiService.authenticateUser(formData.username, formData.password).then((response) => {
|
||||
cookie.save('keystoneAuthTokenId',
|
||||
response.access.token.id,
|
||||
{ path: '/' });
|
||||
dispatch(this.userAuthSuccess(response.access));
|
||||
KeystoneApiService.authenticateUser(formData.username, formData.password).then((result) => {
|
||||
const tokenId = result.request.getResponseHeader('X-Subject-Token');
|
||||
let response = result.response;
|
||||
response.token.id = tokenId;
|
||||
cookie.save('keystoneAuthTokenId', tokenId, { path: '/' });
|
||||
dispatch(this.userAuthSuccess(response.token));
|
||||
ZaqarWebSocketService.init(getState, dispatch);
|
||||
browserHistory.push(nextPath);
|
||||
}).catch((error) => {
|
||||
@ -64,10 +66,10 @@ export default {
|
||||
};
|
||||
},
|
||||
|
||||
userAuthSuccess(keystoneAccess) {
|
||||
userAuthSuccess(token) {
|
||||
return {
|
||||
type: LoginConstants.USER_AUTH_SUCCESS,
|
||||
payload: fromJS(keystoneAccess)
|
||||
payload: fromJS(token)
|
||||
};
|
||||
},
|
||||
|
||||
|
@ -69,7 +69,7 @@ const mapStateToProps = state => {
|
||||
currentPlanName: state.currentPlan.currentPlanName,
|
||||
noPlans: state.plans.get('all').isEmpty(),
|
||||
plansLoaded: state.plans.get('plansLoaded'),
|
||||
user: state.login.getIn(['keystoneAccess', 'user'])
|
||||
user: state.login.getIn(['token', 'user'])
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -70,7 +70,7 @@ export default class NavBar extends React.Component {
|
||||
<li>
|
||||
<a id="NavBar__username">
|
||||
<span className="pficon pficon-user"></span>
|
||||
{this.props.user.get('username')}
|
||||
{this.props.user.get('name')}
|
||||
</a>
|
||||
</li>
|
||||
{this._renderLanguageDropdown()}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { getAppConfig } from '../services/utils';
|
||||
|
||||
let HOST = location.protocol + '//' + location.hostname;
|
||||
let KEYSTONE_URL = getAppConfig().keystone || HOST + ':5000/v2.0';
|
||||
let KEYSTONE_URL = getAppConfig().keystone || HOST + ':5000/v3';
|
||||
|
||||
export const AUTH_URL = KEYSTONE_URL + '/tokens';
|
||||
export const AUTH_URL = KEYSTONE_URL + '/auth/tokens';
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { List, Map, Record } from 'immutable';
|
||||
|
||||
export const InitialLoginState = Record({
|
||||
keystoneAccess: Map(),
|
||||
token: Map(),
|
||||
loginForm: Map({
|
||||
formErrors: List(),
|
||||
formFieldErrors: Map()
|
||||
|
@ -10,7 +10,7 @@ export default function loginReducer(state = initialState, action) {
|
||||
return state.set('isAuthenticating', true);
|
||||
|
||||
case LoginConstants.USER_AUTH_SUCCESS:
|
||||
return state.set('keystoneAccess', action.payload)
|
||||
return state.set('token', action.payload)
|
||||
.set('isAuthenticating', false)
|
||||
.set('isAuthenticated', true);
|
||||
|
||||
|
@ -16,30 +16,74 @@ class KeystoneApiService {
|
||||
}
|
||||
|
||||
authenticateUser(username, password) {
|
||||
return when(request(this.defaultRequest({
|
||||
let req = request(this.defaultRequest({
|
||||
data: JSON.stringify({
|
||||
auth: {
|
||||
tenantName: 'admin',
|
||||
passwordCredentials: {
|
||||
username: username,
|
||||
identity: {
|
||||
methods: ['password'],
|
||||
password: {
|
||||
user: {
|
||||
name: username,
|
||||
domain: {
|
||||
name: 'Default'
|
||||
},
|
||||
password: password
|
||||
}
|
||||
}
|
||||
},
|
||||
scope: {
|
||||
project: {
|
||||
name: 'admin',
|
||||
domain: {
|
||||
name: 'Default'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})));
|
||||
}));
|
||||
|
||||
// We're passing the req object to the next handler in the chain so that we
|
||||
// can inspect response headers later.
|
||||
return when(req, (response) => {
|
||||
return {
|
||||
request: req.request,
|
||||
response
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
authenticateUserViaToken(keystoneAuthTokenId) {
|
||||
return when(request(this.defaultRequest({
|
||||
let req = request(this.defaultRequest({
|
||||
data: JSON.stringify({
|
||||
auth: {
|
||||
tenantName: 'admin',
|
||||
identity: {
|
||||
methods: ['token'],
|
||||
token: {
|
||||
id: keystoneAuthTokenId
|
||||
}
|
||||
},
|
||||
scope: {
|
||||
project: {
|
||||
name: 'admin',
|
||||
domain: {
|
||||
name: 'Default'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})));
|
||||
}));
|
||||
|
||||
// We're passing the req object to the next handler in the chain so that we
|
||||
// can inspect response headers later.
|
||||
return when(req, (response) => {
|
||||
return {
|
||||
request: req.request,
|
||||
response
|
||||
};
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import uuid from 'node-uuid';
|
||||
import when from 'when';
|
||||
|
||||
import { getAuthTokenId, getTenantId, getServiceUrl } from './utils';
|
||||
import { getAuthTokenId, getProjectId, getServiceUrl } from './utils';
|
||||
import { ZAQAR_DEFAULT_QUEUE } from '../constants/ZaqarConstants';
|
||||
import ZaqarActions from '../actions/ZaqarActions';
|
||||
import NotificationActions from '../actions/NotificationActions';
|
||||
@ -42,7 +42,7 @@ export default {
|
||||
headers: {
|
||||
'X-Auth-Token': getAuthTokenId(),
|
||||
'Client-ID': this.clientID,
|
||||
'X-Project-ID': getTenantId()
|
||||
'X-Project-ID': getProjectId()
|
||||
}
|
||||
};
|
||||
this.socket.send(JSON.stringify(message));
|
||||
@ -53,7 +53,7 @@ export default {
|
||||
action: action,
|
||||
headers: {
|
||||
'Client-ID': this.clientID,
|
||||
'X-Project-ID': getTenantId()
|
||||
'X-Project-ID': getProjectId()
|
||||
},
|
||||
body: body
|
||||
};
|
||||
|
@ -8,32 +8,32 @@ import store from '../store';
|
||||
* It gives precedence to urls stored in the app.conf file over
|
||||
* the ones exposed through the serviceCatalog.
|
||||
*/
|
||||
export function getServiceUrl(serviceName, urlType='publicURL', appConfig=getAppConfig()) {
|
||||
export function getServiceUrl(serviceName, urlType='public', appConfig=getAppConfig()) {
|
||||
let serviceUrl = appConfig[serviceName] || getFromServiceCatalog(serviceName, urlType);
|
||||
if(!serviceUrl) {
|
||||
throw Error(`URL for service ${serviceName} can not be found`);
|
||||
}
|
||||
let tenantId = getTenantId();
|
||||
return serviceUrl.replace('%(tenant_id)s', tenantId);
|
||||
return serviceUrl.replace('%(project_id)s', getProjectId());
|
||||
}
|
||||
|
||||
function getFromServiceCatalog(serviceName, urlType) {
|
||||
let endpoint = store.getState().login
|
||||
.getIn(['keystoneAccess', 'serviceCatalog'], List())
|
||||
return store.getState().login
|
||||
.getIn(['token', 'catalog'], List())
|
||||
.find(service => service.get('name') === serviceName, null, Map())
|
||||
.get('endpoints', List()).first();
|
||||
return endpoint ? endpoint.get(urlType) : undefined;
|
||||
.get('endpoints', List())
|
||||
.find(endpoint => endpoint.get('interface') === urlType, null, Map())
|
||||
.get('url');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Keystone Auth Token ID
|
||||
*/
|
||||
export function getAuthTokenId() {
|
||||
return store.getState().login.getIn(['keystoneAccess', 'token', 'id']);
|
||||
return store.getState().login.getIn(['token', 'id']);
|
||||
}
|
||||
|
||||
export function getTenantId() {
|
||||
return store.getState().login.getIn(['keystoneAccess', 'token', 'tenant', 'id']);
|
||||
export function getProjectId() {
|
||||
return store.getState().login.getIn(['token', 'project', 'id']);
|
||||
}
|
||||
|
||||
export function getAppConfig() {
|
||||
|
Loading…
Reference in New Issue
Block a user