diff --git a/.gitignore b/.gitignore index 58715c5ca..8b2454cfd 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,9 @@ # css src/**/*.css + +# IDE - Intelij +.idea # IDE - VSCode .vscode/* !.vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json index 6c5d748e8..570123de2 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,4 @@ { - "editor.formatOnSave": true, "prettier.eslintIntegration": true, "prettier.singleQuote": true, "prettier.trailingComma": "none", diff --git a/src/common/openshiftHelpers.js b/src/common/openshiftHelpers.js index a714f4506..b519316f3 100644 --- a/src/common/openshiftHelpers.js +++ b/src/common/openshiftHelpers.js @@ -34,78 +34,24 @@ const findOpenshiftResource = ( * @param {Object} resourceDef The definition of the OpenShift Resource. * @param {Object} resToFind The OpenShift Resource itself. By default this needs only to contain a name. * @param {Function} compareFn A custom function for comparing resources, determines if a resource is found. + * @param {Object} resToCreateDef The definition of the OpenShift Resource to create. e.g find kind: Project, but create kind: ProjectRequest + * @param {Object} resToCreateObj The OpenShift Resource to create */ -const findOrCreateOpenshiftResource = (resourceDef, resource, compareFn) => - findOpenshiftResource(resourceDef, resource, compareFn).then(foundResource => { +const findOrCreateOpenshiftResource = ( + resourceDef, + resourceToFind, + compareFn, + resourceToCreateDef, + resourceToCreateObj +) => + findOpenshiftResource(resourceDef, resourceToFind, compareFn).then(foundResource => { if (!foundResource) { - return create(resourceDef, resource); + if (resourceToCreateDef && resourceToCreateObj) { + return create(resourceToCreateDef, resourceToCreateObj); + } + create(resourceDef, resourceToFind); } return Promise.resolve(foundResource); }); -const namespaceRequestDef = { - name: 'projectrequests', - version: 'v1', - group: 'project.openshift.io' -}; -const namespaceRequestResource = name => ({ - kind: 'ProjectRequest', - metadata: { - name - } -}); -const namespaceDef = { - name: 'projects', - version: 'v1', - group: 'project.openshift.io' -}; -const namespaceResource = name => ({ - kind: 'projects', - metadata: { - name - } -}); -const statefulSetDef = namespace => ({ - name: 'statefulsets', - group: 'apps', - version: 'v1beta1', - namespace -}); -const routeDef = namespace => ({ - name: 'routes', - group: 'route.openshift.io', - version: 'v1', - namespace -}); -const serviceInstanceDef = namespace => ({ - name: 'serviceinstances', - namespace, - version: 'v1beta1', - group: 'servicecatalog.k8s.io' -}); -const serviceDef = namespace => ({ - name: 'services', - namespace, - version: 'v1' -}); -const secretDef = namespace => ({ - name: 'secrets', - version: 'v1', - namespace -}); - -export { - buildValidProjectNamespaceName, - cleanUsername, - findOrCreateOpenshiftResource, - findOpenshiftResource, - namespaceRequestDef, - namespaceRequestResource, - namespaceDef, - serviceInstanceDef, - namespaceResource, - statefulSetDef, - routeDef, - serviceDef, - secretDef -}; +export { buildValidProjectNamespaceName, findOrCreateOpenshiftResource, findOpenshiftResource }; diff --git a/src/common/openshiftResourceDefinitions.js b/src/common/openshiftResourceDefinitions.js new file mode 100644 index 000000000..b6d19c026 --- /dev/null +++ b/src/common/openshiftResourceDefinitions.js @@ -0,0 +1,62 @@ +const namespaceRequestDef = { + name: 'projectrequests', + version: 'v1', + group: 'project.openshift.io' +}; +const namespaceRequestResource = name => ({ + kind: 'ProjectRequest', + metadata: { + name + } +}); +const namespaceDef = { + name: 'projects', + version: 'v1', + group: 'project.openshift.io' +}; +const namespaceResource = name => ({ + kind: 'projects', + metadata: { + name + } +}); +const statefulSetDef = namespace => ({ + name: 'statefulsets', + group: 'apps', + version: 'v1beta1', + namespace +}); +const routeDef = namespace => ({ + name: 'routes', + group: 'route.openshift.io', + version: 'v1', + namespace +}); +const serviceInstanceDef = namespace => ({ + name: 'serviceinstances', + namespace, + version: 'v1beta1', + group: 'servicecatalog.k8s.io' +}); +const serviceDef = namespace => ({ + name: 'services', + namespace, + version: 'v1' +}); +const secretDef = namespace => ({ + name: 'secrets', + version: 'v1', + namespace +}); + +export { + namespaceRequestDef, + namespaceRequestResource, + namespaceDef, + serviceInstanceDef, + namespaceResource, + statefulSetDef, + routeDef, + serviceDef, + secretDef +}; diff --git a/src/common/serviceInstanceHelpers.js b/src/common/serviceInstanceHelpers.js index c02518ed7..bb7505a4e 100644 --- a/src/common/serviceInstanceHelpers.js +++ b/src/common/serviceInstanceHelpers.js @@ -1,4 +1,8 @@ /* eslint class-methods-use-this: ["error", { "exceptMethods": ["isTransformable", "transform"] }] */ +import { OpenShiftWatchEvents } from '../services/openshiftServices'; +import { GET_WALKTHROUGH_SERVICE } from '../redux/constants/walkthroughServicesConstants'; +import { FULFILLED_ACTION } from '../redux/helpers'; + class DefaultServiceInstanceTransform { isTransformable() { return true; @@ -31,29 +35,29 @@ class AMQServiceInstanceTransform { } } -class CRUDAppInstanceTransform { +class EnMasseServiceInstanceTransform { isTransformable(siInfo) { - return siInfo.name === DEFAULT_SERVICES.CRUD_APP; + return siInfo.name === DEFAULT_SERVICES.ENMASSE; } transform(siInfo) { const defaultTransform = new DefaultServiceInstanceTransform().transform(siInfo); - defaultTransform.spec.clusterServicePlanExternalName = 'default'; + defaultTransform.spec.parameters = { + name: siInfo.username + }; + defaultTransform.spec.clusterServicePlanExternalName = 'unlimited-standard'; return defaultTransform; } } -class EnMasseServiceInstanceTransform { +class CRUDAppInstanceTransform { isTransformable(siInfo) { - return siInfo.name === DEFAULT_SERVICES.ENMASSE; + return siInfo.name === DEFAULT_SERVICES.CRUD_APP; } transform(siInfo) { const defaultTransform = new DefaultServiceInstanceTransform().transform(siInfo); - defaultTransform.spec.parameters = { - name: siInfo.username - }; - defaultTransform.spec.clusterServicePlanExternalName = 'unlimited-standard'; + defaultTransform.spec.clusterServicePlanExternalName = 'default'; return defaultTransform; } } @@ -66,11 +70,13 @@ class MessagingAppServiceInstanceTransform { transform(siInfo) { const defaultTransform = new DefaultServiceInstanceTransform().transform(siInfo); defaultTransform.spec.clusterServicePlanExternalName = 'default'; + defaultTransform.spec.parameters = { - MESSAGING_SERVICE_PASSWORD: siInfo.amqCredentials.password, - MESSAGING_SERVICE_USER: siInfo.amqCredentials.username, - MESSAGING_SERVICE_HOST: siInfo.amqCredentials.url + MESSAGING_SERVICE_PASSWORD: siInfo.otherData.password, + MESSAGING_SERVICE_USER: siInfo.otherData.username, + MESSAGING_SERVICE_HOST: siInfo.otherData.url }; + return defaultTransform; } } @@ -84,6 +90,7 @@ const DEFAULT_SERVICES = { CRUD_APP: 'spring-boot-rest-http-crud', MESSAGING_APP: 'nodejs-messaging-work-queue-frontend' }; + const DEFAULT_TRANSFORMS = [ new EnMasseServiceInstanceTransform(), new AMQServiceInstanceTransform(), @@ -113,10 +120,36 @@ const buildServiceInstanceResourceObj = (siInfo, transforms = DEFAULT_TRANSFORMS const buildServiceInstanceCompareFn = si => res => res.spec.clusterServiceClassExternalName === si.spec.clusterServiceClassExternalName; +const handleWalkthroughOneRoutes = (dispatch, event) => { + if ( + event.type === OpenShiftWatchEvents.OPENED || + event.type === OpenShiftWatchEvents.CLOSED || + event.type === OpenShiftWatchEvents.DELETED + ) { + return; + } + + const route = event.payload; + if ( + route && + route.spec && + route.spec.to && + (route.spec.to.name === DEFAULT_SERVICES.CRUD_APP || route.spec.to.name === DEFAULT_SERVICES.MESSAGING_APP) + ) { + dispatch({ + type: FULFILLED_ACTION(GET_WALKTHROUGH_SERVICE), + payload: route + }); + } +}; + export { + buildServiceInstanceCompareFn, buildServiceInstanceResourceObj, + CRUDAppInstanceTransform, + DEFAULT_SERVICES, DefaultServiceInstanceTransform, EnMasseServiceInstanceTransform, - buildServiceInstanceCompareFn, - DEFAULT_SERVICES + handleWalkthroughOneRoutes, + MessagingAppServiceInstanceTransform }; diff --git a/src/pages/tutorial/task/task.js b/src/pages/tutorial/task/task.js index fcf2a8662..2ed540e8f 100644 --- a/src/pages/tutorial/task/task.js +++ b/src/pages/tutorial/task/task.js @@ -6,16 +6,19 @@ import { noop, Alert, Button, ButtonGroup, Checkbox, Grid, Icon, ProgressBar } f import { connect, reduxActions } from '../../../redux'; import Breadcrumb from '../../../components/breadcrumb/breadcrumb'; import AsciiDocTemplate from '../../../components/asciiDocTemplate/asciiDocTemplate'; -import { provisionWalkthroughOne } from '../../../services/walkthroughProvisionServices'; +import { prepareWalkthroughNamespace, walkthroughs } from '../../../services/walkthroughServices'; class TaskPage extends React.Component { state = { task: 0, verifications: {}, verificationsChecked: false }; componentDidMount() { this.loadThread(); - const { provisionWalkthroughOne } = this.props; + const { prepareWalkthroughOne, prepareWalkthroughOneA } = this.props; if (this.props.match.params.id === '1') { - provisionWalkthroughOne(this.props.middlewareServices.amqCredentials); + prepareWalkthroughOne(this.props.middlewareServices.amqCredentials); + } + if (this.props.match.params.id === '1A') { + prepareWalkthroughOneA(this.props.middlewareServices.enmasseCredentials); } } @@ -287,7 +290,8 @@ TaskPage.propTypes = { }), getThread: PropTypes.func, middlewareServices: PropTypes.object, - provisionWalkthrough: PropTypes.func, + prepareWalkthroughOne: PropTypes.func, + prepareWalkthroughOneA: PropTypes.func, setProgress: PropTypes.func, thread: PropTypes.object, user: PropTypes.object @@ -306,9 +310,11 @@ TaskPage.defaultProps = { getThread: noop, middlewareServices: { data: {}, - amqCredentials: {} + amqCredentials: {}, + enmasseCredentials: {} }, - provisionWalkthrough: noop, + prepareWalkthroughOne: noop, + prepareWalkthroughOneA: noop, setProgress: noop, thread: null, user: null @@ -316,7 +322,9 @@ TaskPage.defaultProps = { const mapDispatchToProps = dispatch => ({ getThread: (language, id) => dispatch(reduxActions.threadActions.getThread(language, id)), - provisionWalkthrough: amqCredentials => provisionWalkthroughOne(dispatch, amqCredentials), + prepareWalkthroughOne: amqCredentials => prepareWalkthroughNamespace(dispatch, walkthroughs.one, amqCredentials), + prepareWalkthroughOneA: enmasseCredentials => + prepareWalkthroughNamespace(dispatch, walkthroughs.oneA, enmasseCredentials), setProgress: progress => dispatch(reduxActions.userActions.setProgress(progress)) }); diff --git a/src/redux/reducers/walkthroughServiceReducers.js b/src/redux/reducers/walkthroughServiceReducers.js index f31f8d853..a62ada941 100644 --- a/src/redux/reducers/walkthroughServiceReducers.js +++ b/src/redux/reducers/walkthroughServiceReducers.js @@ -10,8 +10,7 @@ const initialState = { const walkthroughServiceReducers = (state = initialState, action) => { if (action.type === FULFILLED_ACTION(GET_WALKTHROUGH_SERVICE)) { const createData = Object.assign({}, state.walkthroughServices.services); - createData[action.payload.spec.to.name] = action.payload; - console.log('Create Data', createData); + createData[`${action.payload.metadata.namespace}-${action.payload.spec.to.name}`] = action.payload; return Object.assign({}, state, { walkthroughServices: { ...state.walkthroughServices, diff --git a/src/services/middlewareServices.js b/src/services/middlewareServices.js index d467cd460..5f32a98cb 100644 --- a/src/services/middlewareServices.js +++ b/src/services/middlewareServices.js @@ -1,16 +1,26 @@ -import { list, create, watch, update, currentUser, OpenShiftWatchEvents } from './openshiftServices'; +import { watch, update, currentUser, OpenShiftWatchEvents } from './openshiftServices'; import { middlewareTypes } from '../redux/constants'; import { FULFILLED_ACTION } from '../redux/helpers'; -import { buildServiceInstanceResourceObj, DEFAULT_SERVICES } from '../common/serviceInstanceHelpers'; +import { + buildServiceInstanceCompareFn, + buildServiceInstanceResourceObj, + DEFAULT_SERVICES +} from '../common/serviceInstanceHelpers'; import { buildValidProjectNamespaceName, - namespaceRequestDef, - namespaceDef, + findOpenshiftResource, + findOrCreateOpenshiftResource +} from '../common/openshiftHelpers'; +import { + namespaceResource, namespaceRequestResource, + namespaceDef, + namespaceRequestDef, + serviceInstanceDef, statefulSetDef, - routeDef, - secretDef -} from '../common/openshiftHelpers'; + secretDef, + routeDef +} from '../common/openshiftResourceDefinitions'; const WALKTHROUGH_SERVICES = [ DEFAULT_SERVICES.ENMASSE, @@ -59,15 +69,16 @@ const mockMiddlewareServices = (dispatch, mockData) => { const manageMiddlewareServices = dispatch => { currentUser().then(user => { const userNamespace = buildValidProjectNamespaceName(user.username, 'walkthrough-projects'); - const namespaceObj = namespaceRequestResource(userNamespace); + const namespaceObj = namespaceResource(userNamespace); + const namespaceRequestObj = namespaceRequestResource(userNamespace); - findOpenshiftResource(namespaceDef, namespaceObj) - .then(foundResource => { - if (!foundResource) { - return create(namespaceRequestDef, namespaceObj); - } - return foundResource; - }) + findOrCreateOpenshiftResource( + namespaceDef, + namespaceObj, + resObj => resObj.metadata.name === userNamespace, + namespaceRequestDef, + namespaceRequestObj + ) .then(() => { const siObjs = WALKTHROUGH_SERVICES.map(name => buildServiceInstanceResourceObj({ namespace: userNamespace, name, user }) @@ -75,15 +86,15 @@ const manageMiddlewareServices = dispatch => { return Promise.all( siObjs.map(siObj => findOrCreateOpenshiftResource( - buildServiceInstanceDef(userNamespace), + serviceInstanceDef(userNamespace), siObj, - resObj => resObj.spec.clusterServiceClassExternalName === siObj.spec.clusterServiceClassExternalName + buildServiceInstanceCompareFn(siObj) ) ) ); }) .then(() => { - watch(buildServiceInstanceDef(userNamespace)).then(watchListener => + watch(serviceInstanceDef(userNamespace)).then(watchListener => watchListener.onEvent(handleServiceInstanceWatchEvents.bind(null, dispatch)) ); watch(statefulSetDef(userNamespace)).then(watchListener => @@ -96,17 +107,6 @@ const manageMiddlewareServices = dispatch => { }); }; -/** - * Construct an OpenShift Resource Definition for a ServiceInstance. - * @param {string} namespace The namespace to reference in the definition. - */ -const buildServiceInstanceDef = namespace => ({ - name: 'serviceinstances', - namespace, - version: 'v1beta1', - group: 'servicecatalog.k8s.io' -}); - /** * Handle an event that occured while watching the AMQ StatefulSet. * @param {string} namespace The namespace to perform actions on, based on events. @@ -165,14 +165,12 @@ const handleEnmasseCredentialsWatchEvents = (dispatch, namespace, event) => { const secret = event.payload; if (secret.metadata.name.includes('enmasse-standard') && secret.metadata.name.includes('credentials')) { const amqpHost = window.atob(secret.data.messagingHost); - const amqpPort = window.atob(secret.data.messagingAmqpPort); const username = window.atob(secret.data.username); const password = window.atob(secret.data.password); - const amqpURL = `amqp://${amqpHost}:${amqpPort}?amqp.saslMechanisms=PLAIN`; dispatch({ type: FULFILLED_ACTION(middlewareTypes.GET_ENMASSE_CREDENTIALS), - payload: { url: amqpURL, username, password } + payload: { url: amqpHost, username, password } }); } }; @@ -245,7 +243,7 @@ const handleAMQServiceInstanceWatchEvents = event => { event.payload.metadata.annotations = {}; } event.payload.metadata.annotations[dashboardUrl] = `http://${route.spec.host}`; - update(buildServiceInstanceDef(event.payload.metadata.namespace), event.payload); + update(serviceInstanceDef(event.payload.metadata.namespace), event.payload); }); }; @@ -295,33 +293,4 @@ const handleEnmasseServiceInstanceWatchEvents = event => { } }; -/** - * Helper function for finding a single OpenShift Resource. - * @param {Object} openshiftResourceDef The definition of the OpenShift Resource. - * @param {Object} resToFind The OpenShift Resource itself. By default this needs only to contain a name. - * @param {Function} compareFn A custom function for comparing resources, determines if a resource is found. - */ -const findOpenshiftResource = ( - openshiftResourceDef, - resToFind, - compareFn = resObj => resObj.metadata.name === resToFind.metadata.name -) => - list(openshiftResourceDef) - .then(listResponse => (listResponse && listResponse.items ? listResponse.items : [])) - .then(resourceObjs => resourceObjs.find(resObj => compareFn(resObj))); - -/** - * Helper function for creating an OpenShift Resource if it doesn't exist already. - * @param {Object} openshiftResourceDef The definition of the OpenShift Resource. - * @param {Object} resToFind The OpenShift Resource itself. By default this needs only to contain a name. - * @param {Function} compareFn A custom function for comparing resources, determines if a resource is found. - */ -const findOrCreateOpenshiftResource = (openshiftResourceDef, resToFind, compareFn) => - findOpenshiftResource(openshiftResourceDef, resToFind, compareFn).then(foundResource => { - if (!foundResource) { - return create(openshiftResourceDef, resToFind); - } - return Promise.resolve(foundResource); - }); - export { manageMiddlewareServices, mockMiddlewareServices }; diff --git a/src/services/walkthroughProvisionServices.js b/src/services/walkthroughProvisionServices.js deleted file mode 100644 index 88365fb10..000000000 --- a/src/services/walkthroughProvisionServices.js +++ /dev/null @@ -1,92 +0,0 @@ -import { - buildValidProjectNamespaceName, - findOpenshiftResource, - findOrCreateOpenshiftResource, - namespaceRequestDef, - namespaceRequestResource, - namespaceDef, - namespaceResource, - serviceInstanceDef, - routeDef -} from '../common/openshiftHelpers'; -import { currentUser, create, watch, OpenShiftWatchEvents } from './openshiftServices'; -import { - DEFAULT_SERVICES, - buildServiceInstanceResourceObj, - buildServiceInstanceCompareFn -} from '../common/serviceInstanceHelpers'; -import { FULFILLED_ACTION } from '../redux/helpers'; -import { GET_WALKTHROUGH_SERVICE } from '../redux/constants/walkthroughServicesConstants'; - -/** - * Provisions the services required for Walkthrough 1 into a username prefixed namespace. - * @param {Object} amqCredentials The credentials from the AMQ instance, including URL. - */ -// eslint-disable-next-line consistent-return -const provisionWalkthroughOne = (dispatch, amqCredentials) => { - if (!window.OPENSHIFT_CONFIG.mockData) { - return currentUser().then(user => { - const namespace = buildValidProjectNamespaceName(user.username, 'walkthrough-one'); - const siDef = serviceInstanceDef(namespace); - return findOpenshiftResource(namespaceDef, namespaceResource(namespace)) - .then(foundResource => { - if (!foundResource) { - return create(namespaceRequestDef, namespaceRequestResource(namespace)); - } - return foundResource; - }) - .then(() => { - const messagingAppSiInfo = { - namespace, - name: DEFAULT_SERVICES.MESSAGING_APP, - user, - amqCredentials - }; - const messagingSiResource = buildServiceInstanceResourceObj(messagingAppSiInfo); - return findOrCreateOpenshiftResource( - siDef, - messagingSiResource, - buildServiceInstanceCompareFn(messagingSiResource) - ); - }) - .then(() => { - const crudAppSiInfo = { - namespace, - name: DEFAULT_SERVICES.CRUD_APP - }; - const crudSiResource = buildServiceInstanceResourceObj(crudAppSiInfo); - return findOrCreateOpenshiftResource(siDef, crudSiResource, buildServiceInstanceCompareFn(crudSiResource)); - }) - .then(() => { - watch(routeDef(namespace)).then(watchListener => - watchListener.onEvent(handleWalkthoughOneRoutes.bind(null, dispatch)) - ); - }); - }); - } -}; - -const handleWalkthoughOneRoutes = (dispatch, event) => { - if ( - event.type === OpenShiftWatchEvents.OPENED || - event.type === OpenShiftWatchEvents.CLOSED || - event.type === OpenShiftWatchEvents.DELETED - ) { - return; - } - - const route = event.payload; - if ( - route && - route.spec && - route.spec.to && - (route.spec.to.name === DEFAULT_SERVICES.CRUD_APP || route.spec.to.name === DEFAULT_SERVICES.MESSAGING_APP) - ) { - dispatch({ - type: FULFILLED_ACTION(GET_WALKTHROUGH_SERVICE), - payload: route - }); - } -}; - -export { provisionWalkthroughOne }; diff --git a/src/services/walkthroughServices.js b/src/services/walkthroughServices.js new file mode 100644 index 000000000..52c7c1911 --- /dev/null +++ b/src/services/walkthroughServices.js @@ -0,0 +1,108 @@ +import { watch, currentUser } from './openshiftServices'; +import { buildValidProjectNamespaceName, findOrCreateOpenshiftResource } from '../common/openshiftHelpers'; +import { + buildServiceInstanceCompareFn, + buildServiceInstanceResourceObj, + CRUDAppInstanceTransform, + DEFAULT_SERVICES, + handleWalkthroughOneRoutes, + MessagingAppServiceInstanceTransform +} from '../common/serviceInstanceHelpers'; +import { + namespaceResource, + namespaceRequestResource, + namespaceDef, + namespaceRequestDef, + serviceInstanceDef, + routeDef +} from '../common/openshiftResourceDefinitions'; + +/** + * Walkthroughs definitions, each root level object represents one walkthrough, each contains: + * - suffix of the namespace ${username}-${suffix} + * - list of services needed for the walkthrough, listed by service catalog names + * - ServiceInstances transforms allowing to customise the services e.g. add parameters + */ +const walkthroughs = { + one: { + namespaceSuffix: 'walkthrough-one', + services: [DEFAULT_SERVICES.CRUD_APP, DEFAULT_SERVICES.MESSAGING_APP], + transforms: [new CRUDAppInstanceTransform(), new MessagingAppServiceInstanceTransform()], + watchers: [ + { + resource: namespace => routeDef(namespace), + handlerFn: handleWalkthroughOneRoutes + } + ] + }, + oneA: { + namespaceSuffix: 'walkthrough-one-a', + services: [DEFAULT_SERVICES.CRUD_APP, DEFAULT_SERVICES.MESSAGING_APP], + transforms: [new CRUDAppInstanceTransform(), new MessagingAppServiceInstanceTransform()], + watchers: [ + { + resource: namespace => routeDef(namespace), + handlerFn: handleWalkthroughOneRoutes + } + ] + } +}; + +/** + * Prepare namespace for the given walkthrough: + * - Setup a user-specific projects namespace if it doesn't already exist. This + * will house the users services. + * - Provision one of each walkthrough services into the namespace + * @param dispatch + * @param walkthrough + * @param siInfoOtherData other data that will be added as siInfo.otherData ={} object, can be used to pass data into transforms + */ +const prepareWalkthroughNamespace = (dispatch, walkthrough, siInfoOtherData) => { + if (!window.OPENSHIFT_CONFIG.mockData) { + return currentUser().then(user => { + const userNamespace = buildValidProjectNamespaceName(user.username, walkthrough.namespaceSuffix); + const namespaceObj = namespaceResource(userNamespace); + const namespaceRequestObj = namespaceRequestResource(userNamespace); + + findOrCreateOpenshiftResource( + namespaceDef, + namespaceObj, + resObj => resObj.metadata.name === userNamespace, + namespaceRequestDef, + namespaceRequestObj + ) + .then(() => { + const siObjs = walkthrough.services.map(name => + buildServiceInstanceResourceObj( + { + namespace: userNamespace, + name, + user, + otherData: siInfoOtherData + }, + walkthrough.transforms + ) + ); + return Promise.all( + siObjs.map(siObj => + findOrCreateOpenshiftResource( + serviceInstanceDef(userNamespace), + siObj, + buildServiceInstanceCompareFn(siObj) + ) + ) + ); + }) + .then(() => { + walkthrough.watchers.forEach(watcher => { + watch(watcher.resource(userNamespace)).then(watchListener => + watchListener.onEvent(watcher.handlerFn.bind(null, dispatch)) + ); + }); + }); + }); + } + return null; +}; + +export { prepareWalkthroughNamespace, walkthroughs };