Getting 502 error in Nodejs Hosted Target

@dchiesa1 

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.jsonScreenshot from 2021-07-05 16-01-22.png

 

 

 

 

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 PMstderrsvr.0npm ERR! virtualhost@1.0.0 start: `node .`
Jul 5, 2021 3:44:34 PMstderrsvr.0npm ERR! Exit status 1
Jul 5, 2021 3:44:34 PMstderrsvr.0npm ERR!
Jul 5, 2021 3:44:34 PMstderrsvr.0npm ERR! Failed at the virtualhost@1.0.0 start script.
Jul 5, 2021 3:44:34 PMstderrsvr.0npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
Jul 5, 2021 3:44:34 PMstderrsvr.0npm ERR! errno 1
Jul 5, 2021 3:44:34 PMstderrsvr.0fs.js:646
Jul 5, 2021 3:44:34 PMstderrsvr.0return binding.open(pathModule._makeLong(path), stringToFlags(flags), mode);
Jul 5, 2021 3:44:34 PMstderrsvr.0^
Jul 5, 2021 3:44:34 PMstderrsvr.0 
Jul 5, 2021 3:44:34 PMstderrsvr.0Error: EROFS: read-only file system, open '/root/.apigee-edge-tokens'
Jul 5, 2021 3:44:34 PMstderrsvr.0at Object.fs.openSync (fs.js:646:18)
Jul 5, 2021 3:44:34 PMstderrsvr.0at Object.fs.writeFileSync (fs.js:1299:33)
Jul 5, 2021 3:44:34 PMstderrsvr.0at Object.stashToken (/node_modules/apigee-edge-js/lib/tokenMgmt.js:122:6)
Jul 5, 2021 3:44:34 PMstderrsvr.0at /node_modules/apigee-edge-js/lib/connection.js:77:17
Jul 5, 2021 3:44:34 PMstderrsvr.0at Request._callback (/node_modules/apigee-edge-js/lib/common.js:91:7)
Jul 5, 2021 3:44:34 PMstderrsvr.0at Request.self.callback (/node_modules/request/request.js:185:22)
Jul 5, 2021 3:44:34 PMstderrsvr.0at emitTwo (events.js:126:13)
Jul 5, 2021 3:44:34 PMstderrsvr.0at Request.emit (events.js:214:7)
Jul 5, 2021 3:44:34 PMstderrsvr.0at Request.<anonymous> (/node_modules/request/request.js:1161:10)
Jul 5, 2021 3:44:34 PMstderrsvr.0at emitOne (events.js:116:13)
Jul 5, 2021 3:44:34 PMstderrsvr.0npm ERR! code ELIFECYCLE

 

 

 

Solved Solved
0 1 839
1 ACCEPTED 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);
  });

 

 

 

View solution in original post

1 REPLY 1

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);
  });