blob: c349d9006c3ab1a3281b34038736e9d0dd4c1b7c [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
/**
*
* Retrieve API configuration from the API Gateway:
*
* Parameters (all as fields in the message JSON object)
* gwUrlV2 Required when accesstoken is provided. The V2 API Gateway base path (i.e. http://gw.com)
* gwUrl Required. The API Gateway base path (i.e. http://gw.com)
* gwUser Optional. The API Gateway authentication
* gwPwd Optional. The API Gateway authentication
* __ow_user Optional. Set to the authenticated API authors's namespace when valid authentication is supplied.
* namespace Required if __ow_user not specified. Namespace of API author
* tenantInstance Optional. Instance identifier used when creating the specific API GW Tenant
* accesstoken Optional. Dynamic API GW auth. Overrides gwUser/gwPwd
* spaceguid Optional. Namespace unique id.
* basepath Optional. Base path or API name of the API.
* If not provided, all APIs for the namespace are returned
* relpath Optional. Must be defined with 'operation'. Filters API result to path/operation
* operation Optional. Must be defined with 'relpath'. Filters API result to path/operation
* outputFormat Optional. Defaults to 'swagger'. Possible values:
* 'apigw' = return API as obtained from the API Gateway
* 'swagger' = return API as swagger compliant JSON
*
* NOTE: The package containing this action will be bound to the following values:
* gwUrl, gwAuth
* As such, the caller to this action should normally avoid explicitly setting
* these values
**/
var utils = require('./utils.js');
var utils2 = require('./apigw-utils.js');
function main(message) {
console.log('message: '+JSON.stringify(message)); // ONLY FOR TEMPORARY/LOCAL DEBUG; DON'T ENABLE PERMANENTLY
var badArgMsg = validateArgs(message);
if (badArgMsg) {
return Promise.reject(utils2.makeErrorResponseObject(badArgMsg, (message.__ow_method !== undefined)));
}
message.outputFormat = message.outputFormat || 'swagger';
var tenantInstance = message.tenantInstance || 'openwhisk';
var gwInfo = {
gwUrl: message.gwUrl,
};
if (message.gwUser && message.gwPwd) {
gwInfo.gwAuth = Buffer.from(message.gwUser+':'+message.gwPwd,'ascii').toString('base64');
}
// Set the User-Agent header value
if (message.__ow_headers && message.__ow_headers['user-agent']) {
utils2.setSubUserAgent(message.__ow_headers['user-agent']);
}
// Set namespace override if provided
message.namespace = message.__ow_user || message.namespace;
// This can be invoked as either web action or as a normal action
var calledAsWebAction = message.__ow_method !== undefined;
// Log parameter values
console.log('gwUrl : '+message.gwUrl);
console.log('GW URL V2 : '+message.gwUrlV2);
console.log('__ow_user : '+message.__ow_user);
console.log('namespace : '+message.namespace);
console.log('tenantInstance: '+message.tenantInstance+' / '+tenantInstance);
console.log('accesstoken : '+message.accesstoken);
console.log('spaceguid : '+message.spaceguid);
console.log('limit : '+message.limit);
console.log('skip : '+message.skip);
console.log('basepath/name : '+message.basepath);
console.log('relpath : '+message.relpath);
console.log('operation : '+message.operation);
console.log('outputFormat : '+message.outputFormat);
console.log('calledAsWebAction: '+calledAsWebAction);
if (message.accesstoken) {
gwInfo.gwUrl = message.gwUrlV2;
gwInfo.gwAuth = message.accesstoken;
// Obtain the API from the API GW
return utils2.getApis(gwInfo, message.spaceguid, message.basepath, message.limit, message.skip)
.then(function(endpointDocs) {
console.log('Got '+endpointDocs.length+' APIs');
if (endpointDocs.length === 0) {
console.log('No API found for namespace '+message.namespace + ' with basePath '+ message.basepath);
}
var cliApis = utils2.generateCliResponse(endpointDocs);
console.log('getApi success');
return Promise.resolve(utils2.makeResponseObject({ apis: cliApis }, calledAsWebAction));
})
.catch(function(reason) {
var reasonstr = JSON.parse(utils2.makeJsonString(reason)); // Avoid unnecessary JSON escapes
console.error('API GW failure: '+reasonstr);
return Promise.reject(utils2.makeErrorResponseObject(reasonstr, calledAsWebAction));
});
} else {
// Issue a request to read API(s) from the API GW
// 1. Get the tenant ID associated with the specified namespace and optional tenant instance
// 2. Get the API(s) associated with the tenant ID and optional basepath/apiname
// 3. Format the API(s) per the outputFormat specification
return utils.getTenants(gwInfo, message.namespace, tenantInstance)
.then(function(tenants) {
// If a non-empty tenant array was returned, pick the first one from the list
if (tenants.length === 0) {
console.error('No Tenant found for namespace '+message.namespace);
return Promise.reject('No Tenant found for namespace '+message.namespace);
} else if (tenants.length > 1 ) {
console.error('Multiple tenants found for namespace '+message.namespace+' and tenant instance '+tenantInstance);
return Promise.reject('Internal error. Multiple API Gateway tenants found for namespace '+message.namespace+' and tenant instance '+tenantInstance);
}
console.log('Got a tenant: '+JSON.stringify(tenants[0]));
return Promise.resolve(tenants[0].id);
})
.then(function(tenantId) {
console.log('Got Tenant ID: '+tenantId);
return utils.getApis(gwInfo, tenantId, message.basepath);
})
.then(function(apis) {
console.log('Got API(s)');
if (apis.length === 0) {
console.error('No APIs found for namespace '+message.namespace);
}
var cliApis = utils.generateCliResponse(apis);
console.log('getApi success');
return Promise.resolve(utils2.makeResponseObject({ apis: cliApis }, calledAsWebAction));
})
.catch(function(reason) {
var reasonstr = JSON.parse(utils2.makeJsonString(reason)); // Avoid unnecessary JSON escapes
var rejmsg = 'API GW failure: ' + reasonstr;
console.error(rejmsg);
// Special case handling
// If no tenant id found, then just return an empty list of APIs
if ( (typeof reason === 'string') && (reason.indexOf('No Tenant found') !== -1) ) {
console.log('Namespace has no tenant id yet; returning empty list of APIs');
return Promise.resolve(utils2.makeResponseObject({ apis: utils.generateCliResponse([]) }, calledAsWebAction));
}
return Promise.reject(utils2.makeErrorResponseObject(reasonstr, calledAsWebAction));
});
}
}
function validateArgs(message) {
if(!message) {
console.error('No message argument!');
return 'Internal error. A message parameter was not supplied.';
}
if (!message.gwUrl && !message.gwUrlV2) {
return 'gwUrl is required.';
}
if (!message.__ow_user && !message.namespace) {
return 'Invalid authentication.';
}
if (message.outputFormat && !(message.outputFormat.toLowerCase() === 'apigw' || message.outputFormat.toLowerCase() === 'swagger')) {
return 'Invalid outputFormat value. Valid values are: apigw, swagger';
}
return '';
}
module.exports.main = main;