serverless-vpc-discovery
Version:
Serverless Plugin to modify VPC values
175 lines (174 loc) • 8.79 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
const lambda_function_1 = require("./common/lambda-function");
const globals_1 = __importDefault(require("./globals"));
const validation_1 = require("./validation");
const schema_1 = require("./schema");
const logging_1 = __importDefault(require("./logging"));
const node_config_provider_1 = require("@smithy/node-config-provider");
const config_resolver_1 = require("@smithy/config-resolver");
class VPCPlugin {
constructor(serverless, options, v3Utils) {
this.serverless = serverless;
globals_1.default.serverless = serverless;
globals_1.default.options = options;
if (v3Utils === null || v3Utils === void 0 ? void 0 : v3Utils.log) {
globals_1.default.v3Utils = v3Utils;
}
/* hooks are the actual code that will run when called */
this.hooks = {
"before:package:initialize": this.hookWrapper.bind(this, this.updateFunctionsVpcConfig)
};
serverless.configSchemaHandler.defineCustomProperties(schema_1.customProperties);
serverless.configSchemaHandler.defineFunctionProperties("aws", schema_1.functionProperties);
}
/**
* Wrapper for lifecycle function, initializes variables and checks if enabled.
* @param lifecycleFunc lifecycle function that actually does desired action
*/
hookWrapper(lifecycleFunc) {
return __awaiter(this, void 0, void 0, function* () {
this.validateCustomVPCDiscoveryConfig();
yield this.initResources();
return yield lifecycleFunc.call(this);
});
}
/**
* Validate if the plugin config exists
*/
validateCustomVPCDiscoveryConfig() {
const config = this.serverless.service.custom;
const vpcDiscovery = config && config.vpcDiscovery;
if (vpcDiscovery) {
// support backward compatibility
this.updateVPCDiscoveryConfigCompatibility(vpcDiscovery);
// validate config
try {
// the validateVPCDiscoveryConfig is general for custom and func configs
// so try catch for extend error message with `custom.vpcDiscovery` as a source
(0, validation_1.validateVPCDiscoveryConfig)(vpcDiscovery);
}
catch (e) {
throw new Error(`The \`custom.vpcDiscovery\` is not configured correctly: \n${e} ` + " Please see README for proper setup.");
}
}
}
/**
* This function update VPC Discovery config to support version 2.x config structure and show warning errors
*/
updateVPCDiscoveryConfigCompatibility(vpcDiscovery) {
// support backward compatibility
if (vpcDiscovery && (vpcDiscovery.subnetNames || vpcDiscovery.securityGroupNames)) {
// convert `vpcDiscovery.subnetNames` or `vpcDiscovery.securityGroupNames` to the new config structure
if (!vpcDiscovery.subnets && !vpcDiscovery.securityGroups) {
if (vpcDiscovery.subnetNames) {
vpcDiscovery.subnets = [{ tagKey: "Name", tagValues: vpcDiscovery.subnetNames }];
}
if (vpcDiscovery.securityGroupNames) {
vpcDiscovery.securityGroups = [{ names: vpcDiscovery.securityGroupNames }];
}
logging_1.default.logWarning("The `vpcDiscovery.subnetNames` and `vpcDiscovery.securityGroupNames` options are deprecated " +
"and will be removed in the future. Please see README for proper setup.");
}
}
}
/**
* Setup AWS resources
*/
initResources() {
return __awaiter(this, void 0, void 0, function* () {
// setup AWS resources
yield this.initSLSCredentials();
yield this.initAWSRegion();
const baseVPCDiscovery = this.serverless.service.custom ? this.serverless.service.custom.vpcDiscovery : null;
this.lambdaFunction = new lambda_function_1.LambdaFunction(globals_1.default.credentials, baseVPCDiscovery);
// start of the legacy AWS SDK V2 creds support
// TODO: remove it in case serverless will add V3 support
try {
yield this.lambdaFunction.ec2Wrapper.getVpcs();
}
catch (error) {
if (error.message.includes("Could not load credentials from any providers")) {
globals_1.default.credentials = this.serverless.providers.aws.getCredentials();
this.lambdaFunction = new lambda_function_1.LambdaFunction(globals_1.default.credentials, baseVPCDiscovery);
}
}
});
}
/**
* Init AWS credentials based on sls `provider.profile`
*/
initSLSCredentials() {
return __awaiter(this, void 0, void 0, function* () {
const slsProfile = globals_1.default.options["aws-profile"] || globals_1.default.serverless.service.provider.profile;
globals_1.default.credentials = slsProfile ? yield globals_1.default.getProfileCreds(slsProfile) : null;
});
}
/**
* Init AWS current region based on Node options
*/
initAWSRegion() {
return __awaiter(this, void 0, void 0, function* () {
try {
globals_1.default.currentRegion = yield (0, node_config_provider_1.loadConfig)(config_resolver_1.NODE_REGION_CONFIG_OPTIONS, config_resolver_1.NODE_REGION_CONFIG_FILE_OPTIONS)();
}
catch (err) {
logging_1.default.logInfo("Node region was not found.");
}
});
}
/**
* Updates functions vpc config
* @returns {Promise<object>}
*/
updateFunctionsVpcConfig() {
return __awaiter(this, void 0, void 0, function* () {
logging_1.default.logInfo("Updating VPC config...");
const service = this.serverless.service;
const functions = service.functions || {};
// Sets the serverless's vpc config
// loop through the functions and update VPC config
for (const funcName of Object.keys(functions)) {
const func = service.functions[funcName];
this.updateVPCDiscoveryConfigCompatibility(func.vpcDiscovery);
const funcVPC = yield this.lambdaFunction.getFuncVPC(funcName, func.vpcDiscovery);
if (!funcVPC) {
continue;
}
// init vpc empty config in case not exists
func.vpc = func.vpc || {};
// log warning in case vpc.subnetIds and vpcDiscovery.subnetNames are specified.
if (func.vpc.subnetIds && func.vpcDiscovery && func.vpcDiscovery.subnets) {
logging_1.default.logWarning(`vpc.subnetIds' are specified for the function '${funcName}' ` +
"and overrides 'vpcDiscovery.subnets' discovery config.");
}
// log warning in case vpc.securityGroupIds and vpcDiscovery.securityGroupNames are specified.
if (func.vpc.securityGroupIds && func.vpcDiscovery && func.vpcDiscovery.securityGroups) {
logging_1.default.logWarning(`vpc.securityGroupIds' are specified for the function '${funcName}' ` +
"and overrides 'vpcDiscovery.securityGroups' discovery config.");
}
// set vpc.subnetIds if it does not exists
if (!func.vpc.subnetIds && funcVPC.subnetIds) {
func.vpc.subnetIds = funcVPC.subnetIds;
}
// set vpc.securityGroupIds if it does not exists
if (!func.vpc.securityGroupIds && funcVPC.securityGroupIds) {
func.vpc.securityGroupIds = funcVPC.securityGroupIds;
}
}
return service.functions;
});
}
}
module.exports = VPCPlugin;