I have created nodejs hosted target but getting 504 error . I checked the runtime logs as well and getting the below error but code is working successfully in local.
PS : I checked the build logs as well and it has installed all the dependencies of package.json
const express = require("express")
const path = require('path')
const app = express()
const apigeejs = require('apigee-edge-js'),
common = apigeejs.utility,
apigee = apigeejs.apigee,
sprintf = require('sprintf-js').sprintf,
//Getopt = require('node-getopt'),
version = '20210330-1323';
var PORT = process.env.port || 9000
// View Engine Setup
//app.set("views", path.join(__dirname))
//app.set("view engine", "ejs")
app.get("/organization/:org_name/virtualhost/:vhost", function(req, res){
var gVhostRegexp;
//Getting parameter from URL
var org_name = req.params['org_name']
var vhost = req.params['vhost']
console.log(org_name,vhost)
//=======================================
//For getting proxies for virtual host
opt = {
options: {
org: org_name,
username: 'username@google.com',
password: 'abc@123',
regexp: vhost
}};
//console.log(opt.options) // For checking opt object
function latestDeployment(proxyDeployment) {
let item = { proxyname: proxyDeployment.name, deployments: [] };
proxyDeployment.environment.forEach(environmentDeployment => {
//console.log(JSON.stringify(environmentDeployment, null, 2) + '\n');
environmentDeployment.revision.forEach(rev => {
let list = item.deployments.find(x => x.revision == rev.name);
if (!list) {
list = { revision: rev.name, environments: [] };
item.deployments.push(list);
}
list.environments.push(environmentDeployment.name);
});
});
return item;
}
if (opt.options.regexp) {
gVhostRegexp = new RegExp(opt.options.regexp);
}
apigee
.connect(common.optToOptions(opt))
.then(org =>
org.proxies.get({})
.then(proxies => {
if (!Array.isArray(proxies) && proxies.proxies) {
proxies = proxies.proxies.map(x => x.name); // map to array of strings
}
if (proxies.length > 0) {
let endpointReducer = (apiproxy, revision) =>
(p, endpoint) =>
p.then(acc =>
org.proxies.getEndpoint({ apiproxy, revision, endpoint })
.then(r => [...acc, { endpoint, virtualHosts: r.connection.virtualHost }]));
let proxyReducer = null;
let deploymentReducer = (proxyName) =>
(p, revEnvironment) =>
p.then(acc => {
if (!revEnvironment.environments || revEnvironment.environments.length == 0) {
return acc;
}
return org.proxies.getProxyEndpoints({ apiproxy: proxyName, revision: revEnvironment.revision })
.then(async endpoints => {
//console.log('endpoints: ' + JSON.stringify(endpoints));
let reduction = await endpoints.reduce(endpointReducer(proxyName, revEnvironment.revision), Promise.resolve([]));
//console.log('reduction: ' + JSON.stringify(reduction));
if (opt.options.regexp) {
reduction = reduction.filter(endpt =>
endpt.virtualHosts.filter(item => gVhostRegexp.test(item)).length > 0);
}
return (reduction.length) ? [...acc, {
name: revEnvironment.revision,
environments: revEnvironment.environments,
endpoints: reduction
}] : acc;
});
});
// look only at the latest deployed revision of each proxy
proxyReducer = (p, name) =>
p.then(acc =>
org.proxies.getDeployments({ name })
.then(result => latestDeployment(result))
.then(async latest => {
//console.log(JSON.stringify(latest));
let r = await latest.deployments.reduce(deploymentReducer(name), Promise.resolve([]));
return (r.length) ? [...acc, { proxy: name, revisions: r }] : acc;
}));
return proxies
.reduce(proxyReducer, Promise.resolve([]))
.then(results => {
results = results.filter(item => item); // null item means no regexp match for that proxy
// console.log(JSON.stringify({ results, count: results.length }, null, 2) + '\n');
res.send(JSON.stringify({ results, count: results.length }, null, 2) + '\n');
});
}
}))
.catch(e => {
console.log(e);
console.log(e.stack);
});
// res.send({
// "orgname":org_name,
// "vhost":vhost
// })
})
app.listen(PORT, function(error){
if (error) throw error
console.log("Server created Successfully on PORT", PORT)
})
5, 2021 3:44:34 PM | stderr | svr.0 | npm ERR! virtualhost@1.0.0 start: `node .` |
Jul 5, 2021 3:44:34 PM | stderr | svr.0 | npm ERR! Exit status 1 |
Jul 5, 2021 3:44:34 PM | stderr | svr.0 | npm ERR! |
Jul 5, 2021 3:44:34 PM | stderr | svr.0 | npm ERR! Failed at the virtualhost@1.0.0 start script. |
Jul 5, 2021 3:44:34 PM | stderr | svr.0 | npm ERR! This is probably not a problem with npm. There is likely additional logging output above. |
Jul 5, 2021 3:44:34 PM | stderr | svr.0 | npm ERR! errno 1 |
Jul 5, 2021 3:44:34 PM | stderr | svr.0 | fs.js:646 |
Jul 5, 2021 3:44:34 PM | stderr | svr.0 | return binding.open(pathModule._makeLong(path), stringToFlags(flags), mode); |
Jul 5, 2021 3:44:34 PM | stderr | svr.0 | ^ |
Jul 5, 2021 3:44:34 PM | stderr | svr.0 | |
Jul 5, 2021 3:44:34 PM | stderr | svr.0 | Error: EROFS: read-only file system, open '/root/.apigee-edge-tokens' |
Jul 5, 2021 3:44:34 PM | stderr | svr.0 | at Object.fs.openSync (fs.js:646:18) |
Jul 5, 2021 3:44:34 PM | stderr | svr.0 | at Object.fs.writeFileSync (fs.js:1299:33) |
Jul 5, 2021 3:44:34 PM | stderr | svr.0 | at Object.stashToken (/node_modules/apigee-edge-js/lib/tokenMgmt.js:122:6) |
Jul 5, 2021 3:44:34 PM | stderr | svr.0 | at /node_modules/apigee-edge-js/lib/connection.js:77:17 |
Jul 5, 2021 3:44:34 PM | stderr | svr.0 | at Request._callback (/node_modules/apigee-edge-js/lib/common.js:91:7) |
Jul 5, 2021 3:44:34 PM | stderr | svr.0 | at Request.self.callback (/node_modules/request/request.js:185:22) |
Jul 5, 2021 3:44:34 PM | stderr | svr.0 | at emitTwo (events.js:126:13) |
Jul 5, 2021 3:44:34 PM | stderr | svr.0 | at Request.emit (events.js:214:7) |
Jul 5, 2021 3:44:34 PM | stderr | svr.0 | at Request.<anonymous> (/node_modules/request/request.js:1161:10) |
Jul 5, 2021 3:44:34 PM | stderr | svr.0 | at emitOne (events.js:116:13) |
Jul 5, 2021 3:44:34 PM | stderr | svr.0 | npm ERR! code ELIFECYCLE |
Solved! Go to Solution.
Yes
The script is using apigee-edge-js, which tries to re-use tokens by writing them to a cache file (~/.apigee-edge-tokens). The error message is telling us that the write of that file is prevented by the runtime environment.
Sadly, at this moment, I don't think there is a way to tell the apigee-edge-js library to NOT cache tokens.
Let me look into it.
OK I've updated the apigee-edge-js library to handle the error it might encounter when writing the apigee-edge-tokens file. You need v0.4.27 of the library to get that enhancement.
This is the code I used to demonstrate it.
// index.js
// ------------------------------------------------------------------
/* jshint esversion:9, node:true, strict:implied */
/* global process, console, Buffer */
const express = require('express'),
path = require('path'),
app = express(),
apigeejs = require('apigee-edge-js'),
apigee = apigeejs.apigee,
PORT = process.env.port || 9000,
version = '20210707-1040';
const initialConnectOptions = require('./initialConnectOptions.json');
// initialConnectOptions.json should have this form:
// {
// "org" : "bootstrap_orgname",
// "username" : "myuser@somewhere.com",
// "password" : "SuperSecret!!"
// }
//
// The bootstrap_orgname need not be the same as the orgname that
// you query later. But, the account that authenticates to that
// bootstrap_orgname must have access to the org specified later.
// Otherwise, you will encounter a runtime error.
//
let org = null;
let globalToken = null;
const connectOptions = org => ({
org,
token: globalToken,
username : initialConnectOptions.username
});
const retainToken = org =>
globalToken = org.conn.requestHeaders.authorization.substr(7);
function latestDeployment(proxyDeployment) {
let item = { proxyname: proxyDeployment.name, deployments: [] };
proxyDeployment.environment.forEach(environmentDeployment => {
//console.log(JSON.stringify(environmentDeployment, null, 2) + '\n');
environmentDeployment.revision.forEach(rev => {
let list = item.deployments.find(x => x.revision == rev.name);
if (!list) {
list = { revision: rev.name, environments: [] };
item.deployments.push(list);
}
list.environments.push(environmentDeployment.name);
});
});
return item;
}
function handler(req, res) {
var subjectOrg = req.params['org_name'];
var vhost = req.params['vhost'];
console.log(subjectOrg, vhost);
//=======================================
//For getting proxies for virtual host
let vhostRegexp = new RegExp(vhost);
apigee
.connect(connectOptions(subjectOrg))
.then(org => {
retainToken(org);
return org.proxies.get({})
.then(proxies => {
if (!Array.isArray(proxies) && proxies.proxies) {
proxies = proxies.proxies.map(x => x.name); // map to array of strings
}
if (proxies.length > 0) {
let endpointReducer = (apiproxy, revision) =>
(p, endpoint) =>
p.then(acc =>
org.proxies.getEndpoint({ apiproxy, revision, endpoint })
.then(r => [...acc, { endpoint, virtualHosts: r.connection.virtualHost }]));
let deploymentReducer = (proxyName) =>
(p, revEnvironment) =>
p.then(acc => {
if (!revEnvironment.environments || revEnvironment.environments.length == 0) {
return acc;
}
return org.proxies.getProxyEndpoints({ apiproxy: proxyName, revision: revEnvironment.revision })
.then(async endpoints => {
//console.log('endpoints: ' + JSON.stringify(endpoints));
let reduction = await endpoints.reduce(endpointReducer(proxyName, revEnvironment.revision), Promise.resolve([]));
//console.log('reduction: ' + JSON.stringify(reduction));
reduction = reduction.filter(endpt =>
endpt.virtualHosts.filter(item => vhostRegexp.test(item)).length > 0);
return (reduction.length) ? [...acc, {
name: revEnvironment.revision,
environments: revEnvironment.environments,
endpoints: reduction
}] : acc;
});
});
// look only at the latest deployed revision of each proxy
let proxyReducer = (p, name) =>
p.then(acc =>
org.proxies.getDeployments({ name })
.then(result => latestDeployment(result))
.then(async latest => {
//console.log(JSON.stringify(latest));
let r = await latest.deployments.reduce(deploymentReducer(name), Promise.resolve([]));
return (r.length) ? [...acc, { proxy: name, revisions: r }] : acc;
}));
return proxies
.reduce(proxyReducer, Promise.resolve([]))
.then(results => {
results = results.filter(item => item); // null item means no regexp match for that proxy
// console.log(JSON.stringify({ results, count: results.length }, null, 2) + '\n');
res.send(JSON.stringify({ results, count: results.length }, null, 2) + '\n');
});
}
else {
console.log('no proxies');
res.send(JSON.stringify({}, null, 2) + '\n');
}
});
})
.catch(e => {
console.log(e);
res.status(500)
.send(JSON.stringify({ error: "internal error" }, null, 2) + '\n');
});
}
app.get("/organization/:org_name/virtualhost/:vhost", handler);
app.get("/o/:org_name/v/:vhost", handler);
// perform the initial "bootstrap" connection
apigee
.connect(initialConnectOptions)
.then(initialOrg => {
retainToken(initialOrg);
app.listen(PORT, function(error) {
if (error) throw error;
console.log("Server created Successfully on PORT", PORT);
});
})
.catch(e => {
console.log(e);
console.log(e.stack);
});
Yes
The script is using apigee-edge-js, which tries to re-use tokens by writing them to a cache file (~/.apigee-edge-tokens). The error message is telling us that the write of that file is prevented by the runtime environment.
Sadly, at this moment, I don't think there is a way to tell the apigee-edge-js library to NOT cache tokens.
Let me look into it.
OK I've updated the apigee-edge-js library to handle the error it might encounter when writing the apigee-edge-tokens file. You need v0.4.27 of the library to get that enhancement.
This is the code I used to demonstrate it.
// index.js
// ------------------------------------------------------------------
/* jshint esversion:9, node:true, strict:implied */
/* global process, console, Buffer */
const express = require('express'),
path = require('path'),
app = express(),
apigeejs = require('apigee-edge-js'),
apigee = apigeejs.apigee,
PORT = process.env.port || 9000,
version = '20210707-1040';
const initialConnectOptions = require('./initialConnectOptions.json');
// initialConnectOptions.json should have this form:
// {
// "org" : "bootstrap_orgname",
// "username" : "myuser@somewhere.com",
// "password" : "SuperSecret!!"
// }
//
// The bootstrap_orgname need not be the same as the orgname that
// you query later. But, the account that authenticates to that
// bootstrap_orgname must have access to the org specified later.
// Otherwise, you will encounter a runtime error.
//
let org = null;
let globalToken = null;
const connectOptions = org => ({
org,
token: globalToken,
username : initialConnectOptions.username
});
const retainToken = org =>
globalToken = org.conn.requestHeaders.authorization.substr(7);
function latestDeployment(proxyDeployment) {
let item = { proxyname: proxyDeployment.name, deployments: [] };
proxyDeployment.environment.forEach(environmentDeployment => {
//console.log(JSON.stringify(environmentDeployment, null, 2) + '\n');
environmentDeployment.revision.forEach(rev => {
let list = item.deployments.find(x => x.revision == rev.name);
if (!list) {
list = { revision: rev.name, environments: [] };
item.deployments.push(list);
}
list.environments.push(environmentDeployment.name);
});
});
return item;
}
function handler(req, res) {
var subjectOrg = req.params['org_name'];
var vhost = req.params['vhost'];
console.log(subjectOrg, vhost);
//=======================================
//For getting proxies for virtual host
let vhostRegexp = new RegExp(vhost);
apigee
.connect(connectOptions(subjectOrg))
.then(org => {
retainToken(org);
return org.proxies.get({})
.then(proxies => {
if (!Array.isArray(proxies) && proxies.proxies) {
proxies = proxies.proxies.map(x => x.name); // map to array of strings
}
if (proxies.length > 0) {
let endpointReducer = (apiproxy, revision) =>
(p, endpoint) =>
p.then(acc =>
org.proxies.getEndpoint({ apiproxy, revision, endpoint })
.then(r => [...acc, { endpoint, virtualHosts: r.connection.virtualHost }]));
let deploymentReducer = (proxyName) =>
(p, revEnvironment) =>
p.then(acc => {
if (!revEnvironment.environments || revEnvironment.environments.length == 0) {
return acc;
}
return org.proxies.getProxyEndpoints({ apiproxy: proxyName, revision: revEnvironment.revision })
.then(async endpoints => {
//console.log('endpoints: ' + JSON.stringify(endpoints));
let reduction = await endpoints.reduce(endpointReducer(proxyName, revEnvironment.revision), Promise.resolve([]));
//console.log('reduction: ' + JSON.stringify(reduction));
reduction = reduction.filter(endpt =>
endpt.virtualHosts.filter(item => vhostRegexp.test(item)).length > 0);
return (reduction.length) ? [...acc, {
name: revEnvironment.revision,
environments: revEnvironment.environments,
endpoints: reduction
}] : acc;
});
});
// look only at the latest deployed revision of each proxy
let proxyReducer = (p, name) =>
p.then(acc =>
org.proxies.getDeployments({ name })
.then(result => latestDeployment(result))
.then(async latest => {
//console.log(JSON.stringify(latest));
let r = await latest.deployments.reduce(deploymentReducer(name), Promise.resolve([]));
return (r.length) ? [...acc, { proxy: name, revisions: r }] : acc;
}));
return proxies
.reduce(proxyReducer, Promise.resolve([]))
.then(results => {
results = results.filter(item => item); // null item means no regexp match for that proxy
// console.log(JSON.stringify({ results, count: results.length }, null, 2) + '\n');
res.send(JSON.stringify({ results, count: results.length }, null, 2) + '\n');
});
}
else {
console.log('no proxies');
res.send(JSON.stringify({}, null, 2) + '\n');
}
});
})
.catch(e => {
console.log(e);
res.status(500)
.send(JSON.stringify({ error: "internal error" }, null, 2) + '\n');
});
}
app.get("/organization/:org_name/virtualhost/:vhost", handler);
app.get("/o/:org_name/v/:vhost", handler);
// perform the initial "bootstrap" connection
apigee
.connect(initialConnectOptions)
.then(initialOrg => {
retainToken(initialOrg);
app.listen(PORT, function(error) {
if (error) throw error;
console.log("Server created Successfully on PORT", PORT);
});
})
.catch(e => {
console.log(e);
console.log(e.stack);
});