UNPKG

@aws-amplify/graphql-schema-generator

Version:
242 lines 10.4 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.invokeSchemaInspectorLambda = exports.sleep = exports.provisionSchemaInspectorLambda = exports.getHostVpc = void 0; const client_iam_1 = require("@aws-sdk/client-iam"); const client_lambda_1 = require("@aws-sdk/client-lambda"); const fs = __importStar(require("fs-extra")); const ora_1 = __importDefault(require("ora")); const vpc_helper_cluster_1 = require("./vpc-helper-cluster"); const vpc_helper_proxy_1 = require("./vpc-helper-proxy"); const vpc_helper_instance_1 = require("./vpc-helper-instance"); const spinner = (0, ora_1.default)(''); const getHostVpc = async (hostname, region) => { const proxyResult = await (0, vpc_helper_proxy_1.checkHostInDBProxies)(hostname, region); if (proxyResult) { return proxyResult; } const warning = (clusterOrInstance) => { return (`The host you provided is for an RDS ${clusterOrInstance}. Consider using an RDS Proxy as your data source instead.\n` + 'See the documentation for a discussion of how an RDS proxy can help you scale your application more effectively.'); }; const clusterResult = await (0, vpc_helper_cluster_1.checkHostInDBClusters)(hostname, region); if (clusterResult) { console.warn(warning('cluster')); return clusterResult; } const instanceResult = await (0, vpc_helper_instance_1.checkHostInDBInstances)(hostname, region); if (instanceResult) { console.warn(warning('instance')); return instanceResult; } return undefined; }; exports.getHostVpc = getHostVpc; const provisionSchemaInspectorLambda = async (lambdaName, vpc, region) => { var _a, _b, _c, _d; const roleName = `${lambdaName}-execution-role`; let createLambda = true; const iamRole = await createRoleIfNotExists(roleName, region); const existingLambda = await getSchemaInspectorLambda(lambdaName, region); spinner.start('Provisioning a function to introspect the database schema...'); try { if (existingLambda) { const subnetIds = vpc.subnetAvailabilityZoneConfig.map((sn) => sn.subnetId); const vpcConfigMismatch = ((_b = (_a = existingLambda.VpcConfig) === null || _a === void 0 ? void 0 : _a.SecurityGroupIds) === null || _b === void 0 ? void 0 : _b.sort().join()) !== vpc.securityGroupIds.sort().join() || ((_d = (_c = existingLambda.VpcConfig) === null || _c === void 0 ? void 0 : _c.SubnetIds) === null || _d === void 0 ? void 0 : _d.sort().join()) !== subnetIds.sort().join(); if (vpcConfigMismatch) { await deleteSchemaInspectorLambdaRole(lambdaName, region); createLambda = true; } else { await updateSchemaInspectorLambda(lambdaName, region); createLambda = false; } } if (createLambda) { await createSchemaInspectorLambda(lambdaName, iamRole, vpc, region); } } catch (err) { spinner.fail('Failed to provision a function to introspect the database schema.'); console.debug(`Error provisioning a function to introspect the database schema: ${err}`); throw err; } spinner.succeed('Successfully provisioned a function to introspect the database schema.'); }; exports.provisionSchemaInspectorLambda = provisionSchemaInspectorLambda; const getSchemaInspectorLambda = async (lambdaName, region) => { const lambdaClient = new client_lambda_1.LambdaClient({ region }); const params = { FunctionName: lambdaName, }; try { const response = await lambdaClient.send(new client_lambda_1.GetFunctionCommand(params)); return response.Configuration; } catch (err) { return undefined; } }; const deleteSchemaInspectorLambdaRole = async (lambdaName, region) => { const lambdaClient = new client_lambda_1.LambdaClient({ region }); const params = { FunctionName: lambdaName, }; const FUNCTION_DELETE_DELAY = 10000; await lambdaClient.send(new client_lambda_1.DeleteFunctionCommand(params)); await (0, exports.sleep)(FUNCTION_DELETE_DELAY); }; const createSchemaInspectorLambda = async (lambdaName, iamRole, vpc, region) => { const lambdaClient = new client_lambda_1.LambdaClient({ region }); const subnetIds = vpc.subnetAvailabilityZoneConfig.map((sn) => sn.subnetId); const params = { Code: { ZipFile: await fs.readFile(`${__dirname}/../rds-schema-inspector.zip`), }, PackageType: 'Zip', FunctionName: lambdaName, Handler: 'index.handler', Role: iamRole.Arn, Runtime: 'nodejs20.x', VpcConfig: { SecurityGroupIds: vpc.securityGroupIds, SubnetIds: subnetIds, }, Timeout: 30, }; const response = await lambdaClient.send(new client_lambda_1.CreateFunctionCommand(params)); await (0, client_lambda_1.waitUntilFunctionActive)({ client: lambdaClient, maxWaitTime: 600 }, { FunctionName: response.FunctionName }); }; const updateSchemaInspectorLambda = async (lambdaName, region) => { const lambdaClient = new client_lambda_1.LambdaClient({ region }); const params = { FunctionName: lambdaName, ZipFile: await fs.readFile(`${__dirname}/../rds-schema-inspector.zip`), }; await lambdaClient.send(new client_lambda_1.UpdateFunctionCodeCommand(params)); }; const createRoleIfNotExists = async (roleName, region) => { let role = await getRole(roleName, region); const ROLE_PROPAGATION_DELAY = 10000; if (!role) { role = await createRole(roleName, region); await (0, exports.sleep)(ROLE_PROPAGATION_DELAY); } return role; }; const sleep = async (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)); exports.sleep = sleep; const createPolicy = async (policyName, region) => { const client = new client_iam_1.IAMClient({ region }); const command = new client_iam_1.CreatePolicyCommand({ PolicyName: policyName, PolicyDocument: JSON.stringify({ Version: '2012-10-17', Statement: [ { Effect: 'Allow', Resource: '*', Action: ['ec2:CreateNetworkInterface', 'ec2:DescribeNetworkInterfaces', 'ec2:DeleteNetworkInterface'], }, { Effect: 'Allow', Action: ['logs:CreateLogGroup', 'logs:CreateLogStream', 'logs:PutLogEvents'], Resource: ['arn:aws:logs:*:*:*'], }, ], }), }); const result = await client.send(command); await (0, client_iam_1.waitUntilPolicyExists)({ client, maxWaitTime: 30 }, { PolicyArn: result.Policy.Arn }); return result.Policy; }; const createRole = async (roleName, region) => { const client = new client_iam_1.IAMClient({ region }); const policy = await createPolicy(`${roleName}-policy`, region); const command = new client_iam_1.CreateRoleCommand({ AssumeRolePolicyDocument: JSON.stringify({ Version: '2012-10-17', Statement: [ { Effect: 'Allow', Principal: { Service: 'lambda.amazonaws.com', }, Action: 'sts:AssumeRole', }, ], }), RoleName: roleName, }); const result = await client.send(command); const attachPolicyCommand = new client_iam_1.AttachRolePolicyCommand({ PolicyArn: policy.Arn, RoleName: roleName, }); await client.send(attachPolicyCommand); await (0, client_iam_1.waitUntilRoleExists)({ client, maxWaitTime: 30 }, { RoleName: roleName }); return result.Role; }; const getRole = async (roleName, region) => { const client = new client_iam_1.IAMClient({ region }); const command = new client_iam_1.GetRoleCommand({ RoleName: roleName, }); try { const response = await client.send(command); return response.Role; } catch (err) { if (err.name == 'NoSuchEntityException') { return undefined; } throw err; } }; const invokeSchemaInspectorLambda = async (funcName, dbConfig, query, region) => { const client = new client_lambda_1.LambdaClient({ region }); const encoder = new TextEncoder(); const command = new client_lambda_1.InvokeCommand({ FunctionName: funcName, Payload: encoder.encode(JSON.stringify({ config: dbConfig, query, })), LogType: client_lambda_1.LogType.Tail, }); const { Payload } = await client.send(command); const result = Buffer.from(Payload).toString(); const resultJson = JSON.parse(result); if (resultJson.errorMessage) { throw new Error(`Error occurred while fetching the database metadata: ${resultJson.errorMessage}`); } return resultJson; }; exports.invokeSchemaInspectorLambda = invokeSchemaInspectorLambda; //# sourceMappingURL=vpc-helper.js.map