Skip to content

Commit

Permalink
Merge pull request acmeair#1 from wasperf/microservices
Browse files Browse the repository at this point in the history
Microservices
  • Loading branch information
jdmcclur committed Nov 12, 2015
2 parents 009bd06 + 6a03ac9 commit 1f7f16f
Show file tree
Hide file tree
Showing 15 changed files with 1,059 additions and 35 deletions.
12 changes: 9 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

# Acme Air in NodeJS

An implementation of the Acme Air sample application for NodeJS. This implementation can support multiple datastores, can run in several application modes, and can support running on a variety of runtime platforms including standalone bare metal system, Virtual Machines, docker containers, IBM Bluemix, IBM Bluemix Container Service.
Expand Down Expand Up @@ -47,16 +48,21 @@ Assume MongoDB started on 127.0.0.1:27017
### Run Acmeair in Monolithic on Local

node app.js
### Run Acmeair in Micro-Service on Local

### Run Acmeair in Micro-Service on Local

node authservice-app.js
node customerservice_app.js
node flightbookingservice_app.js

set AUTH_SERVICE=localhost:9443 or export AUTH_SERVICE=localhost:9443
set CUSTOMER_SERVICE=localhost:9443 or export CUSTOMER_SERVICE=localhost:9443
set FLIGHTBOOKING_SERVICE=localhost:9443 or export FLIGHTBOOKING_SERVICE=localhost:9443
node app.js

### Run Acmeair in Micro-Service with Netflix Hystrix Stream enabled on Local


node authservice-app.js
set AUTH_SERVICE=localhost:9443 or export AUTH_SERVICE=localhost:9443
set enableHystrix=true or export enableHystrix=true
Expand Down
33 changes: 25 additions & 8 deletions README_Bluemix.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,31 +50,48 @@ Cloudant:

#### You must first deploy the Acmeair in Monolithic mode before proceeding.

#### Push the authentication service
#### Push the extra services

cf push acmeair-authservice --no-start -c "node authservice-app.js"
cf push acmeair-as --no-start -c "node authservice_app.js"
cf push acmeair-cs --no-start -c "node customerservice_app.js"
cf push acmeair-fbs --no-start -c "node flightbookingservice_app.js"

Again, "acmeair-authservice" needs to be unique.
Again, the application names needs to be unique.

#### Bind the mongodb service to service applications

cf bind-service acmeair-as acmeairMongo
cf bind-service acmeair-cs acmeairMongo
cf bind-service acmeair-fbs acmeairMongo

or

cf bind-service acmeair-as acmeairCL
cf bind-service acmeair-cs acmeairCL
cf bind-service acmeair-fbs acmeairCL

#### Now that the authentication service is running, you can configure the web application to use it by setting the following user defined environment

variable stopping the application first


cf stop acmeair-nodejs
cf set-env acmeair-nodejs AUTH_SERVICE acmeair-authservice.mybluemix.net:80
cf set-env acmeair-nodejs AUTH_SERVICE acmeair-as.mybluemix.net:80
cf set-env acmeair-nodejs CUSTOMER_SERVICE acmeair-cs.mybluemix.net:80
cf set-env acmeair-nodejs FLIGHTBOOKING_SERVICE acmeair-authservice.mybluemix.net:80 acmeair-fbs.mybluemix.net:80

#### Enable Hystrix by setting the following user defined environment variable

cf set-env acmeair-nodejs enableHystrix true

#### Now start the authentication service and the web application

#### Now start the services and the web application

cf start acmeair-authservice
cf start acmeair-as
cf start acmeair-cs
cf start acmeair-fbs
cf start acmeair-nodejs

Now go to http://acmeair-nodejs.mybluemix.net and login. That login uses the authentication microservice.
Now go to http://acmeair-nodejs.mybluemix.net and login. That login uses the authentication microservice.

#### You can run the Hystrix Dashboard in Bluemix as well. To deploy the Hystrix dashboard, you need to download the WAR file for the dashboard. You
can find a link to the download here: https://github.com/Netflix/Hystrix/wiki/Dashboard#installing-the-dashboard. The following CF CLI command will deploy
Expand Down
2 changes: 1 addition & 1 deletion acmeairhttp/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ module.exports = function (settings) {

var contextRoot = settings.authContextRoot || "/acmeair-auth-service/rest/api"
var location = process.env.AUTH_SERVICE;

var hostAndPort = location.split(":");

var log4js = require('log4js');
Expand Down
31 changes: 30 additions & 1 deletion app.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ logger.info("host:port=="+host+":"+port);

var authService;
var authServiceLocation = process.env.AUTH_SERVICE;

var customerService;
var customerServiceLocation = process.env.CUSTOMER_SERVICE;

var flightbookingService;
var flightbookingServiceLocation = process.env.FLIGHTBOOKING_SERVICE;


if (authServiceLocation)
{
logger.info("Use authservice:"+authServiceLocation);
Expand All @@ -48,6 +56,18 @@ if (authServiceLocation)
}
}

if(customerServiceLocation)
{
logger.info("Use customerservice:"+customerServiceLocation);
customerService = new require('./customerhttp/index.js')(settings);
}

if(flightbookingServiceLocation)
{
logger.info("Use flightbookingservice:"+flightbookingServiceLocation);
flightbookingService = new require('./flightbookinghttp/index.js')(settings);
}

var dbtype = process.env.dbtype || "mongo";

// Calculate the backend datastore type if run inside BLuemix or cloud foundry
Expand All @@ -62,7 +82,7 @@ if(process.env.VCAP_SERVICES){
}
logger.info("db type=="+dbtype);

var routes = new require('./routes/index.js')(dbtype, authService,settings);
var routes = new require('./routes/index.js')(dbtype, authService, customerService, flightbookingService,settings);
var loader = new require('./loader/loader.js')(routes, settings);

// Setup express with 4.0.0
Expand Down Expand Up @@ -92,14 +112,21 @@ app.use(cookieParser()); // parse cookie

var router = express.Router();

// main app
router.post('/login', login);
router.get('/login/logout', logout);

// flight service
router.post('/flights/queryflights', routes.checkForValidSessionCookie, routes.queryflights);
router.post('/bookings/bookflights', routes.checkForValidSessionCookie, routes.bookflights);
router.post('/bookings/cancelbooking', routes.checkForValidSessionCookie, routes.cancelBooking);
router.get('/bookings/byuser/:user', routes.checkForValidSessionCookie, routes.bookingsByUser);

// customer service
router.get('/customer/byid/:user', routes.checkForValidSessionCookie, routes.getCustomerById);
router.post('/customer/byid/:user', routes.checkForValidSessionCookie, routes.putCustomerById);

// probably main app?
router.get('/config/runtime', routes.getRuntimeInfo);
router.get('/config/dataServices', routes.getDataServiceInfo);
router.get('/config/activeDataService', routes.getActiveDataServiceInfo);
Expand All @@ -112,6 +139,8 @@ router.get('/config/countAirports' , routes.countAirports);
//router.get('/loaddb', startLoadDatabase);
router.get('/loader/load', startLoadDatabase);
router.get('/loader/query', loader.getNumConfiguredCustomers);

// ?
router.get('/checkstatus', checkStatus);

if (authService && authService.hystrixStream)
Expand Down
105 changes: 105 additions & 0 deletions customerhttp/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*******************************************************************************
* Copyright (c) 2015 IBM Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/

module.exports = function (settings) {
var module = {};
var http = require('http')

var contextRoot = settings.customerContextRoot || "/acmeair-customer-service/rest/api"
var location = process.env.CUSTOMER_SERVICE;

var hostAndPort = location.split(":");

var log4js = require('log4js');
var logger = log4js.getLogger('customerhttp');
logger.setLevel(settings.loggerLevel);

module.getCustomer = function (userid, callback /* (error, userid) */){

var path = contextRoot+"/customer/byid/" + userid;
var options = {
hostname: hostAndPort[0],
port: hostAndPort[1],
path: path,
method: "GET",
headers: {
'Content-Type': 'application/json'
}
}

logger.debug('getCustomer request:'+JSON.stringify(options));

var request = http.request(options, function(response){
var data='';
response.setEncoding('utf8');
response.on('data', function (chunk) {
data +=chunk;
});
response.on('end', function(){
if (response.statusCode>=400)
callback("StatusCode:"+ response.statusCode+",Body:"+data, null);
else{
callback(null, data);
}
})
});
request.on('error', function(e) {
callback('problem with request: ' + e.message, null);
});
request.end();
}

module.updateCustomer = function (userid, customer, callback /* (error, userid) */){

customerData = JSON.stringify(customer);

var path = contextRoot+"/customer/byid/" + userid;
var options = {
hostname: hostAndPort[0],
port: hostAndPort[1],
path: path,
method: "POST",
headers: {
'Content-Type': 'application/json',
'Content-Length': customerData.length
}
}

logger.debug('updateCustomer request:'+JSON.stringify(options));

var request = http.request(options, function(response){
var data='';
response.setEncoding('utf8');
response.on('data', function (chunk) {
data +=chunk;
});
response.on('end', function(){
if (response.statusCode>=400)
callback("StatusCode:"+ response.statusCode+",Body:"+data, null);
else{
callback(null, data);
}
})
});
request.on('error', function(e) {
callback('problem with request: ' + e.message, null);
});
request.write(customerData);
request.end();
}

return module;
}
113 changes: 113 additions & 0 deletions customerservice/routes/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/*******************************************************************************
* Copyright (c) 2015 IBM Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/

module.exports = function (dbtype, authService, settings) {
var module = {};
var uuid = require('node-uuid');
var log4js = require('log4js');

var logger = log4js.getLogger('customerservice/routes');
logger.setLevel(settings.loggerLevel);

var daModuleName = "../../dataaccess/"+dbtype+"/index.js";
logger.info("Use dataaccess:"+daModuleName);
var dataaccess = new require(daModuleName)(settings);

module.dbNames = dataaccess.dbNames

module.initializeDatabaseConnections = function(callback/*(error)*/) {
dataaccess.initializeDatabaseConnections(callback);
}

module.checkForValidSessionCookie = function(req, res, next) {
logger.debug('checkForValidCookie');
var sessionid = req.cookies.sessionid;
if (sessionid) {
sessiondid = sessionid.trim();
}
if (!sessionid || sessionid == '') {
logger.info('checkForValidCookie - no sessionid cookie so returning 403');
logger.debug('checkForValidCookie - no sessionid cookie so returning 403');
res.sendStatus(403);
return;
}

validateSession(sessionid, function(err, customerid) {
if (err) {
logger.debug('checkForValidCookie - system error validating session so returning 500');
res.sendStatus(500);
return;
}

if (customerid) {
logger.debug('checkForValidCookie - good session so allowing next route handler to be called');
req.acmeair_login_user = customerid;
next();
return;
}
else {
logger.info('checkForValidCookie - bad session so returning 403');
logger.debug('checkForValidCookie - bad session so returning 403');
res.sendStatus(403);
return;
}
});
}

function validateSession(sessionId, callback /* (error, userid) */) {
authService.validateSession(sessionId,callback);
return;
}

module.getCustomerById = function(req, res) {
logger.debug('getting customer by user ' + req.params.user);

getCustomer(req.params.user, function(err, customer) {
if (err) {
res.sendStatus(500);
}

res.send(customer);
});
};

module.putCustomerById = function(req, res) {
logger.debug('putting customer by user ' + req.params.user);

updateCustomer(req.params.user, req.body, function(err, customer) {
if (err) {
res.sendStatus(500);
}
res.send(customer);
});
};

module.initializeDatabaseConnections = function(callback/*(error)*/) {
dataaccess.initializeDatabaseConnections(callback);
}


function getCustomer(username, callback /* (error, Customer) */) {
dataaccess.findOne(module.dbNames.customerName, username, callback);
}

function updateCustomer(login, customer, callback /* (error, Customer) */) {
dataaccess.update(module.dbNames.customerName, customer,callback)
}


return module;
}
Loading

0 comments on commit 1f7f16f

Please sign in to comment.