SAP-BTP-Spielwiese/app1/node_modules/@sap/xsenv/lib/xsservices.js

152 lines
6.5 KiB
JavaScript
Raw Normal View History

'use strict';
var assert = require('assert');
var VError = require('verror');
var debug = require('debug')('xsenv');
var fs = require('fs');
var serviceFilter = require('./filter');
const readCFServices = require('./cfservice').readCFServices;
const readK8SServices = require('./k8sservice').readK8SServices;
const readServiceBindingServices = require('./serviceBindingService').readServiceBindingServices;
exports.getServices = getServices;
exports.filterServices = filterServices;
exports.serviceCredentials = serviceCredentials;
exports.readServices = readServices;
/**
* Looks up and returns bound Cloud Foundry or K8S services.
* If a service is not found - returns default service configuration loaded from a JSON file. The order of lookup is VCAP_SERVICES ->
* mounted secrets path in K8S -> default service configuration.
*
* @param path {string} A string containing the mount path where the secrets are located in K8S. By default is "/etc/secrets/sapcp".
* @param query {object} describes requested Cloud Foundry services, each property value is a filter
* as described in filterCFServices.
* @param servicesFile {string} path to JSON file to load default service configuration (default is default-services.json).
* If null, do not load default service configuration.
*
* @returns {object} with the same properties as in query argument where the value of each
* property is the respective service credentials object.
* @throws Error, if for some of the requested services no or multiple instances are found; Error, if query parameter is not provided
*/
function getServices(arg1, arg2, arg3) {
const path = typeof arg1 === 'string' ? arg1 : undefined;
const query = typeof arg1 === 'string' ? arg2 : arg1;
const servicesFile = typeof arg1 === 'string' ? arg3 : arg2;
assert(query && typeof query === 'object', 'Missing mandatory query parameter');
var defaultServices = loadDefaultServices(servicesFile);
var result = {};
for (var key in query) {
var matches = filterServices(path, query[key]);
if (matches.length === 1) {
result[key] = matches[0].credentials;
} else if (matches.length > 1) {
throw new VError('Found %d services matching %s', matches.length, key);
} else {
// not found in VCAP_SERVICES or K8S => check servicesFile
if (!defaultServices[key]) {
throw new VError('No service matches %s', key);
}
debug('No service in VCAP_SERVICES matches %s. Returning default configuration from %s', key, servicesFile);
result[key] = defaultServices[key];
}
}
return result;
}
function loadDefaultServices(servicesFile) {
var defaultServices = {};
if (servicesFile !== null) {
servicesFile = servicesFile || 'default-services.json';
if (fs.existsSync(servicesFile)) {
debug('Loading default service configuration from %s', servicesFile);
try {
defaultServices = JSON.parse(fs.readFileSync(servicesFile, 'utf8'));
} catch (err) {
throw new VError(err, 'Could not parse %s', servicesFile);
}
}
}
return defaultServices;
}
/**
* Filters for service in service configuration from CloudFoundry (environment variable <code>VCAP_SERVICES</code>)
* or mounted K8S secrets if no results found in <code>VCAP_SERVICES</code>.
*
* @param path {string} A string containing the mount path where the secrets are located in K8S.
* @param filter Filter used to find a bound service, see filterCFServices
* @return Array of objects representing all found service instances (credentials and its meta data)
* @throws Error in case no or multiple matching services are found
*/
function filterServices(arg1, arg2) {
const path = (arguments.length === 1) ? undefined : arg1;
const filter = (arguments.length === 1) ? arg1 : arg2;
let filterResults = serviceFilter.apply(readCFServices(), filter);
debug('CF Service filter with filter: %s, returned: %s.', filter, filterResults);
if (!filterResults || (filterResults && Array.isArray(filterResults) && !filterResults.length)) {
filterResults = serviceFilter.apply(readServiceBindingServices(path), filter);
debug('Service Binding Services filter with filter: %s and path: %s, returned: %s.', filter, (path ? path : 'default'), filterResults);
}
if (!filterResults || (filterResults && Array.isArray(filterResults) && !filterResults.length)) {
filterResults = serviceFilter.apply(readK8SServices(path), filter);
debug('K8s Service filter with filter: %s and path: %s, returned: %s.', filter, (path ? path : 'default'), filterResults);
}
return filterResults;
}
/**
* Reads service credentials configuration from CloudFoundry environment variable <code>VCAP_SERVICES</code>
* or mounted K8S secrets.
*
* @param path {string} A string containing the mount path where the secrets are mounted in K8S environment.
* @param filter Filter used to find a bound Cloud Foundry service, see filterCFServices
* @return Credentials property of found service
* @throws Error in case no or multiple matching services are found
*/
function serviceCredentials(arg1, arg2) {
const path = (arguments.length === 1) ? undefined : arg1;
const filter = (arguments.length === 1) ? arg1 : arg2;
var matches = path
? filterServices(path, filter)
: filterServices(filter);
if (matches.length !== 1) {
throw new VError('Found %d matching services', matches.length);
}
return matches[0].credentials;
}
/**
* Reads service configuration from CloudFoundry environment variable <code>VCAP_SERVICES</code>
* or mounted K8S secrets if <code>VCAP_SERVICES</code> is empty.
*
* @param path {string} A string containing the mount path where the secrets are mounted in K8S environment.
* @param options {object} An object with options to customize behavior. Currently allows only to disable K8s secrets caching.
* @return Object with appropriate services or empty object if no CF or K8S services found.
* @throws Error in case bad CF json or bad path.
*/
function readServices(path, options) {
let cfServices = readCFServices();
if (cfServices && Object.keys(cfServices).length > 0) {
debug('Found VCAP_SERVICES, returning: %s', cfServices);
return cfServices;
}
let serviceBindingServices = readServiceBindingServices(path);
if (serviceBindingServices && Object.keys(serviceBindingServices).length > 0) {
debug('Found Service Bindings, returning: %s', serviceBindingServices);
return serviceBindingServices;
}
let k8sServices = readK8SServices(path, options && options.disableCache);
debug('Empty VCAP_SERVICES, returning K8s services: %s.', JSON.stringify(k8sServices));
return k8sServices || {};
}