Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Bug 522385 - Several exceptions thrown from the cloud foundry code (#183
)
  • Loading branch information
mrennie committed Sep 18, 2017
1 parent 3c74d4d commit c93ef10
Show file tree
Hide file tree
Showing 3 changed files with 171 additions and 91 deletions.
5 changes: 3 additions & 2 deletions modules/orionode/index.js
Expand Up @@ -17,7 +17,8 @@ var express = require('express'),
api = require('./lib/api'),
checkRights = require('./lib/accessRights').checkRights,
log4js = require('log4js'),
logger = log4js.getLogger("response");
logger = log4js.getLogger("response"),
CloudFoundry = require('./lib/cf').CloudFoundry;

var LIBS = path.normalize(path.join(__dirname, 'lib/')),
MINIFIED_ORION_CLIENT = path.normalize(path.join(__dirname, "lib/orion.client")),
Expand Down Expand Up @@ -145,7 +146,7 @@ function startServer(options) {
app.use('/file*', options.authenticate, checkAuthenticated, checkAccessRights, require('./lib/file')(options));
app.use('/workspace*', options.authenticate, checkAuthenticated, checkAccessRights, require('./lib/workspace')(options));
app.use('/gitapi', options.authenticate, checkAuthenticated, require('./lib/git')(options));
app.use('/cfapi', options.authenticate, checkAuthenticated, require('./lib/cf')(options));
app.use('/cfapi', options.authenticate, checkAuthenticated, new CloudFoundry().createRouter(options));
app.use('/prefs', options.authenticate, checkAuthenticated, require('./lib/prefs').router(options));
app.use('/xfer', options.authenticate, checkAuthenticated, require('./lib/xfer').router(options));
if(options.configParams["orion.collab.enabled"]){
Expand Down
75 changes: 45 additions & 30 deletions modules/orionode/lib/cf.js
@@ -1,6 +1,5 @@
/*eslint-env node */
/*******************************************************************************
* Copyright (c) 2016 IBM Corporation and others.
* Copyright (c) 2016, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials are made
* available under the terms of the Eclipse Public License v1.0
* (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution
Expand All @@ -9,32 +8,48 @@
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
var express = require('express');

var apps = require('./cf/apps');
var domains = require('./cf/domains');
var logz = require('./cf/logz');
var manifests = require('./cf/manifests');
var orgs = require('./cf/orgs_spaces');
var plans = require('./cf/plans');
var routes = require('./cf/routes');
var services = require('./cf/services');
var target = require('./cf/target');

module.exports = CF;
function CF(options) {
var fileRoot = options.fileRoot;
if (!fileRoot) { throw new Error('options.fileRoot is required'); }
var router = express.Router();
var express = require('express'),
apps = require('./cf/apps'),
domains = require('./cf/domains'),
logz = require('./cf/logz'),
manifests = require('./cf/manifests').ManifestRouter,
orgs = require('./cf/orgs_spaces'),
plans = require('./cf/plans'),
routes = require('./cf/routes'),
services = require('./cf/services'),
target = require('./cf/target');

router.use("/apps", apps.router(options));
router.use("/domains", domains.router(options));
router.use("/logz", logz.router(options));
router.use("/manifests", manifests.router(options));
router.use("/orgs", orgs.router(options));
router.use("/plans", plans.router(options));
router.use("/routes", routes.router(options));
router.use("/services", services.router(options));
router.use("/target", target.router(options));
return router;
}
/**
* @description Class for setting up cloud foundry support
* @class
*/
class CloudFoundry {
/**
* @description Create a new instance of the class
*/
constructor() {}
/**
* @description Create an express Router for handling /manifests
* @param {?} options The map of options. The option 'fileRoot' must be specified. All other options are optional
* @returns {Router} A new express router
* @throws {Error} If options.filePath is not defined
*/
createRouter(options) {
if (!options || !options.fileRoot) {
throw new Error('options.fileRoot is required');
}
let router = express.Router();
router.use("/apps", apps.router(options));
router.use("/domains", domains.router(options));
router.use("/logz", logz.router(options));
router.use("/manifests", new manifests().createRouter(options));
router.use("/orgs", orgs.router(options));
router.use("/plans", plans.router(options));
router.use("/routes", routes.router(options));
router.use("/services", services.router(options));
router.use("/target", target.router(options));
return router;
}
}

module.exports.CloudFoundry = CloudFoundry;
182 changes: 123 additions & 59 deletions modules/orionode/lib/cf/manifests.js
Expand Up @@ -21,45 +21,69 @@ var target = require("./target");
var tasks = require("../tasks");
var crypto = require('crypto');

module.exports.router = function(options) {
var fileRoot = options.fileRoot;
if (!fileRoot) { throw new Error('options.fileRoot is required'); }
module.exports.retrieveManifestFile = retrieveManifestFile;
module.exports.retrieveProjectFilePath = retrieveProjectFilePath;
module.exports.slugify = slugify;
/**
* @description Class to handle manifests
* @since 16.0
*/
class ManifestRouter {
/**
* @description Create a new instance of the class
*/
constructor() {}
/**
* @description Create an express Router for handling /manifests
* @param {?} options The map of options. The option 'fileRoot' must be specified. All other options are optional
* @returns {Router} A new express router
* @throws {Error} If options.filePath is not defined
*/
createRouter(options) {
if (!options.fileRoot) {
throw new Error('options.fileRoot is required');
}
return express.Router()
.use(bodyParser.json())
.get(this.fileRoot + "*", getManifests)
.get("*", getManifests);
}
}

return express.Router()
.use(bodyParser.json())
.get(fileRoot + "*", getManifests)
.get("*", getManifests);

module.exports.ManifestRouter = ManifestRouter;
/**
* @description Fetch the manifest for the project
* @param {?} req The original request
* @param {?} res The response
*/
function getManifests(req, res){
retrieveManifestFile(req, res)
.then(function(manifest){
var respond = {
"Contents": manifest,
"Type": "Manifest"
};
writeResponse(200, res, null, respond);
}).catch(function(err){
var task = new tasks.Task(res, false, false, 0, false);
target.caughtErrorHandler(task, err);
});
return retrieveManifestFile(req, res)
.then(function(manifest){
writeResponse(200, res, null, {
"Contents": manifest,
"Type": "Manifest"
});
}).catch(function(err){
var task = new tasks.Task(res, false, false, 0, false);
target.caughtErrorHandler(task, err);
});
}

/**
* res is needed because following Java server's patten, /plan and /manifest endpoins don't use task
* task is needed for situation where there was a task created. So that we cannot use res in these cases.
*/
function retrieveManifestFile(req, res, manifestAbsoluteLocation){
module.exports.retrieveManifestFile = retrieveManifestFile = function retrieveManifestFile(req, res, manifestAbsoluteLocation){
return new Promise(function(fulfill,reject) {
var uri = req.originalUrl.substring(req.baseUrl.length + req.contextPath.length);
var uri = req.originalUrl.substring(req.baseUrl.length + (typeof req.contextPath === 'string' ? req.contextPath.length : 0));
req.user.checkRights(req.user.username, uri, req, res, function(){
var filePath = manifestAbsoluteLocation ? manifestAbsoluteLocation : retrieveProjectFilePath(req);
if(!filePath) {
var errorStatus = new Error("Could not find manifest.");
errorStatus.code = "404";
return reject(errorStatus);
}
if(filePath.indexOf("manifest.yml") === -1){
filePath += "manifest.yml";
}
fs.readFile(filePath, "utf8", function(err, fileContent){
fs.readFile(filePath, "utf8", function(err, fileContent) {
if(err && err.code !== "ENOENT") {
var errorStatus = new Error(err.message);
errorStatus.code = "404";
Expand All @@ -72,25 +96,74 @@ function retrieveManifestFile(req, res, manifestAbsoluteLocation){
if (!fileContent) { // if the project doesn't have a manifest.yml
return setDefaultManifestProperties(req);
}
var manifest = yaml.safeLoad(fileContent);
var manifestAST = yamlAstParser.load(fileContent);
var manifest = yaml.safeLoad(fileContent, {
onWarning: function(warning, foo, bar, baz, boo) {
//TODO we should collect these up and forward them
}
});
var manifestAST = yamlAstParser.safeLoad(fileContent, {
onWarning: function(warning, foo, bar, baz, boo) {
//TODO we should collect these up and forward them
}
});
transformManifest(manifest);
symbolResolve(manifest);
return analyzeManifest(manifest, manifestAST, fileContent)
.then(function(){
return setDefaultManifestProperties(req, manifest);
});
.then(function(){
return setDefaultManifestProperties(req, manifest);
});
});
}
};

function setDefaultManifestProperties(req, manifest){
function getDefaultName(rawProjectName){
var nameParts = rawProjectName.split(" --- ", 2);
return nameParts.length > 1 ? nameParts[1] : nameParts[0];
/**
* @description Parses the project path out of the request
* @param {?} req The request to try and get the project path from
* @returns {string} The file path
*/
module.exports.retrieveProjectFilePath = retrieveProjectFilePath = function retrieveProjectFilePath(req){
var projectPath = req.params[0],
file;
if(typeof projectPath === 'string') {
projectPath = projectPath.replace(/^\/file/, "");
}
function getDefaultHost(rawProjectName){
return slugify(rawProjectName);
file = fileUtil.getFile(req, projectPath);
if(file && file.path) {
return file.path;
}
return null;
};

/**
* @description Converts the given string to a form suitable to be used as a 'Slug' in a request.
* Conversion is as follows:
* 1. replace spaces with '-'
* 2. remove all non-word characters
* 3. replace multiple '-' with a single '-'
* 4. trim '-' from the start and end of the string
* @param {string} inputString The string to convert
* @returns {string} The converted string
*/
module.exports.slugify = slugify = function slugify(inputString) {
if(typeof inputString === 'string') {
return inputString.toLowerCase()
.replace(/\s+/g, "-") // Replace spaces with -
.replace(/[^\w\-]+/g, "") // Remove all non-word chars
.replace(/\-\-+/g, "-") // Replace multiple - with single -
.replace(/^-+/, "") // Trim - from start of text
.replace(/-+$/, ""); // Trim - from end of text
}
}

function getDefaultName(rawProjectName){
var nameParts = rawProjectName.split(" --- ", 2);
return nameParts.length > 1 ? nameParts[1] : nameParts[0];
}

function getDefaultHost(rawProjectName){
return slugify(rawProjectName);
}

function setDefaultManifestProperties(req, manifest) {
var rawContentLocationData = req.params[0].split("/");
var rawDefaultProjectName = rawContentLocationData[rawContentLocationData.length - 2];
rawDefaultProjectName = rawDefaultProjectName.replace(/\|/, " --- ");
Expand All @@ -113,8 +186,9 @@ function setDefaultManifestProperties(req, manifest){
}
return manifest;
}
function transformManifest(manifest){
if(!manifest.applications){

function transformManifest(manifest) {
if(!manifest || !manifest.applications){
return; // Do nothing
}
var globals = [];
Expand All @@ -136,7 +210,11 @@ function transformManifest(manifest){
}
});
}
function symbolResolve(manifestNode){

function symbolResolve(manifestNode) {
if(!manifestNode) {
return;
}
if(Array.isArray(manifestNode)){
manifestNode.forEach(function(subNode){
symbolResolve(subNode);
Expand All @@ -151,9 +229,9 @@ function symbolResolve(manifestNode){
});
// Java code also handles ${target-base} case, but it seems useless, will implement when necessary.
}
function analyzeManifest(manifest, manifestAST, fileContent){
if(!manifest.applications){
return Promise.resolve(); // Do nothing
function analyzeManifest(manifest, manifestAST, fileContent) {
if(!manifestAST) {
Promise.resolve();
}
var lineNumbers = [];
var valueWithParent = [];
Expand Down Expand Up @@ -191,7 +269,7 @@ function analyzeManifest(manifest, manifestAST, fileContent){
}else if(manifestAST.hasOwnProperty("value")){
if(!manifestAST.value){ // null case
// find null
nullArray.push(makeInvalidateReject("Empty Propety",getLineNumber(manifestAST.startPosition, manifestAST.endPosition, lineNumbers)));
nullArray.push(makeInvalidateReject("Empty Property",getLineNumber(manifestAST.startPosition, manifestAST.endPosition, lineNumbers)));
return;
}
if(typeof manifestAST.value === "string"){
Expand Down Expand Up @@ -322,18 +400,4 @@ function analyzeManifest(manifest, manifestAST, fileContent){
errorStatus.data = resultJson;
return errorStatus;
}
}
function retrieveProjectFilePath(req){
var projectPath = req.params[0];
var file = fileUtil.getFile(req, projectPath);
return file.path;
}
function slugify(inputString){
return inputString.toLowerCase()
.replace(/\s+/g, "-") // Replace spaces with -
.replace(/[^\w\-]+/g, "") // Remove all non-word chars
.replace(/\-\-+/g, "-") // Replace multiple - with single -
.replace(/^-+/, "") // Trim - from start of text
.replace(/-+$/, ""); // Trim - from end of text
}
};
}

0 comments on commit c93ef10

Please sign in to comment.