├── .eslintrc.json
├── .gitignore
├── LICENSE
├── README.md
├── bin
└── cli.js
├── methods
├── .DS_Store
├── AWS
│ ├── deleteGatewayv2.js
│ ├── gatewayv2.js
│ ├── getGatewayv2.js
│ ├── iam.js
│ ├── lambda.js
│ └── s3.js
├── commands
│ ├── aliases.js
│ ├── apis.js
│ ├── buckets.js
│ ├── functions.js
│ ├── layers.js
│ └── roles.js
└── util
│ ├── archiver.js
│ ├── aws.js
│ ├── chalkColors.js
│ ├── default.js
│ ├── generateEnv.js
│ └── verifyAWS.js
├── npm_package
└── index.js
├── package-lock.json
└── package.json
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "node": true,
5 | "es6": true
6 | },
7 | "plugins": ["react"],
8 | "extends": ["eslint:recommended", "plugin:react/recommended"],
9 | "parserOptions": {
10 | "ecmaVersion": 8,
11 | "sourceType": "module",
12 | "ecmaFeatures": {
13 | "impliedStrict": true,
14 | "jsx": true
15 | }
16 | },
17 | "rules": {
18 | "indent": ["warn", 2],
19 | "no-unused-vars": ["off", { "vars": "local" }],
20 | "prefer-const": "warn",
21 | "quotes": ["warn", "single"],
22 | "react/prop-types": "off",
23 | "semi": ["warn", "always"],
24 | "space-infix-ops": "warn",
25 | "linebreak-style": ["warn", "unix"]
26 | },
27 | "settings": {
28 | "react": { "version": "detect"}
29 | }
30 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 | .env
3 | .vscode/
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 alanajs
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # alanajs
2 |
3 |
4 |
5 |
6 |

7 |
8 |
AWS Lambda and API Gateway, simplified for JavaScript
9 |
10 |
11 |
12 |
13 | [![Issues][issues-shield]][issues-url]
14 | [![MIT License][license-shield]][license-url]
15 |
16 |
17 |
18 |
19 | ## About alanajs
20 |
21 | Make setting up Lambda microservices easier than ever. alanajs is a free, open-source npm package that consolidates functionality provided by AWS SDK and AWS CLI, automating deployment and configuration tasks by making intelligent assumptions about the deployment sequence according to best practices. alanajs makes it easy to deploy Lambda functions with dependencies and layers, and it also simplifies creating routes, APIs, and integrations with Lambda on AWS API Gateway.
22 |
23 | Here is a [Medium](https://medium.com/@jaehyunha/introducing-alanajs-aws-lambda-and-api-gateway-simplified-for-javascript-5108cb8773eb) article describing the story behind alanajs.
24 |
25 | You can also visit us here.
26 |
27 | ## Table of Contents
28 |
29 |
30 | Table of Contents
31 |
32 | - About alanajs
33 | - Getting Started
34 |
37 | - Enhancement and Improvements
38 |
41 | - Reporting Issues
42 | - Contributors
43 | - License
44 |
45 |
46 |
47 | (back to top)
48 |
49 | ## Getting Started
50 |
51 | This section describes the instructions for end users who would like to download the package and connect their AWS account. For developers who would like to contribute to the open-source project, follow these [instructions](#enhancement-and-improvements).
52 |
53 | ### Installation and Setup
54 |
55 | 1. Install alanajs as a package dependency.
56 |
57 | ```sh
58 | npm install alanajs
59 | ```
60 |
61 | 2. Update the `.env` file in the project root directory with the necessary credentials OR see Step 3 to init through the command line.
62 |
63 | ```sh
64 | AWS_ACCESS_KEY_ID=
65 | AWS_SECRET_ACCESS_KEY=
66 | AWS_REGION=
67 | ROLENAME=
68 | S3BUCKETNAME=
69 | AWS_ACCOUNT=
70 | FOLDER=
71 | ```
72 |
73 | 3. Run the follow through the command line to update .env file or create one if it does not exist. Replace the parameters with user's details. Refer to documentation for more details. The DIRECTORY is the main folder to store files, dependencies, and directories as Lambda functions and layers.
74 |
75 | ```sh
76 | alana init [AWS_ACCOUNT] [AWS_REGION] -r [ROLENAME] -b [S3BUCKETNAME] -d [DIRECTORY]
77 | ```
78 |
79 | 4. Import the package to start using alana methods.
80 |
81 | ```sh
82 | import 'alana' from 'alanajs';
83 | ```
84 |
85 | 5. That's it! You are ready to start running code through the command line or by running node [fileName] to execute the functions.
86 |
87 | (back to top)
88 |
89 |

90 |
91 | Figure 1: Create and Update Lambda Function
92 |
93 |
94 |

95 |
96 | Figure 2: Create and Update Lambda Layers
97 |
98 |
99 |
100 |

101 |
102 | Figure 3: Create, Update and Delete Alias
103 |
104 |
105 |
106 |

107 |
108 | Figure 4: Create, Update and Delete API Gateway
109 |
110 |
111 |
112 |

113 |
114 | Figure 5: Create, Update and Delete Routes
115 |
116 |
117 |
118 | (back to top)
119 |
120 | ## Enhancement and Improvements
121 |
122 | This section describes the instructions for developers who would like to contribute to the open-source project. For users who would like to download the package and connect their AWS account, follow these [instructions](#getting-started) instead.
123 |
124 | ### Built With
125 |
126 | The alanajs application was built using the following:
127 |
128 | - Node
129 | - Commander
130 | - AWS SDK for Javascript V3
131 |
132 | 1. Fork the project.
133 |
134 | 2. Create a feature branch.
135 |
136 | ```sh
137 | git checkout -b feature/featureName
138 | ```
139 |
140 | 3. Install package dependencies.
141 |
142 | ```sh
143 | npm install
144 | ```
145 |
146 | 4. Update the `.env` file in the project root directory with the necessary credentials OR init through the command line.
147 |
148 | ```sh
149 | AWS_ACCESS_KEY_ID=
150 | AWS_SECRET_ACCESS_KEY=
151 | AWS_REGION=
152 | ROLENAME=
153 | S3BUCKETNAME=
154 | AWS_ACCOUNT=
155 | FOLDER=
156 | ```
157 |
158 | ```sh
159 | alana init [AWS_ACCOUNT] [AWS_REGION] -r [ROLENAME] -b [S3BUCKETNAME] -d [DIRECTORY]
160 | ```
161 |
162 | 5. Add and commit your changes.
163 |
164 | ```sh
165 | git add ...
166 | git commit -m 'Add some feature functionality'
167 | ```
168 |
169 | 6. Push to the branch.
170 |
171 | ```sh
172 | git push origin feature/featureName
173 | ```
174 |
175 | 7. Open a Pull Request here.
176 |
177 | (back to top)
178 |
179 |
180 | ## Reporting Issues
181 |
182 | Bugs are tracked through GitHub issues. Create an issue on our repository and provide the following information based on this template:
183 |
184 | - **Descriptive title**: Provide a descriptive title for your issue.
185 | - **Describe the issue**: Describe the steps you took leading up to the issue. Try to provide code or screenshots.
186 | - **Expected behavior**: Describe the expected behavior.
187 |
188 |
189 | (back to top)
190 |
191 |
192 | ## Contributors
193 |
194 | - Tin Khin -
195 | Github |
196 | Linkedin
197 | - Eugene Lee -
198 | Github |
199 | Linkedin
200 |
201 | - Amy Liang -
202 | Github |
203 | Linkedin
204 |
205 | - Jae Hyun Ha -
206 | Github |
207 | Linkedin
208 |
209 |
210 | Project Links: Github | Linkedin | Medium | Visit Us
211 |
212 | (back to top)
213 |
214 |
215 | ## License
216 |
217 | Distributed under the MIT License. See the [LICENSE](https://github.com/oslabs-beta/alanajs/blob/master/LICENSE) for details
218 |
219 |
220 |
221 |
222 | [contributors-shield]: https://img.shields.io/github/contributors/oslabs-beta/alanajs.svg?style=for-the-badge
223 | [contributors-url]: https://github.com/oslabs-beta/alanajs/graphs/contributors
224 | [stars-shield]: https://img.shields.io/github/stars/oslabs-beta/alanajs.svg?style=for-the-badge
225 | [stars-url]: https://github.com/oslabs-beta/alanajs/stargazers
226 | [issues-shield]: https://img.shields.io/github/issues/oslabs-beta/alanajs.svg?style=for-the-badge
227 | [issues-url]: https://github.com/oslabs-beta/alanajs/issues
228 | [license-shield]: https://img.shields.io/github/license/oslabs-beta/alanajs.svg?style=for-the-badge
229 | [license-url]: https://github.com/oslabs-beta/alanajs/blob/master/LICENSE
230 | [linkedin-shield]: https://img.shields.io/badge/-LinkedIn-black.svg?style=for-the-badge&logo=linkedin&colorB=555
231 | [linkedin-url]: https://www.linkedin.com/company/alanajs
232 | [product-screenshot]: client/src/Dashboard/assets/img/helios-blue-logo-t.png
233 |
--------------------------------------------------------------------------------
/bin/cli.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | // npm packages
3 | import { program, Command } from 'commander';
4 | import dotenv from 'dotenv';
5 |
6 | // commands
7 | import lambdaFunctions from '../methods/commands/functions.js';
8 | import layers from '../methods/commands/layers.js';
9 | import aliases from '../methods/commands/aliases.js';
10 | import roles from '../methods/commands/roles.js';
11 | import buckets from '../methods/commands/buckets.js';
12 | import apis from '../methods/commands/apis.js';
13 |
14 | // init
15 | import init from '../methods/util/generateEnv.js';
16 |
17 | // consts
18 | import {AwsBucket, AwsRegion, AwsRole } from '../methods/util/aws.js';
19 | import {startingBucket, startingRegion, startingRole, startingFolder} from '../methods/util/default.js';
20 | import { intro, starting, error, fail, finished, code } from '../methods/util/chalkColors.js';
21 |
22 | dotenv.config();
23 |
24 | const envFolder = process.env.FOLDER;
25 |
26 | // local variables
27 | const hasCredentials = !!(process.env.AWS_ACCESS_KEY_ID && process.env.AWS_SECRET_ACCESS_KEY && process.env.AWS_REGION);
28 | const defaultBucket = AwsBucket || startingBucket;
29 | const defaultRegion = AwsRegion || startingRegion;
30 | const defaultRole = AwsRole || startingRole;
31 | const defaultFolder = envFolder || startingFolder;
32 |
33 | console.clear();
34 |
35 | if (!hasCredentials) {
36 | program
37 | . addHelpText('before', intro('Welcome to alanajs.')
38 | + '\nNo AWS credentials were found, so start by issuing the following command:\n\n '
39 | + code('alana init ')
40 | + '\n\nThere are additional options as well. Once the AWS credentials are entered, more options are available to you.'
41 | + '\nCheck out help by attaching the -h or --help flag to the command line'
42 | + '\n see below for the command line usage\n');
43 | }
44 |
45 | program
46 | .command('init')
47 | . addHelpText('before', intro('alanajs\n')
48 | + 'This will initialize or update the .ENV file needed to run alanajs. Admin privileges are required to verify the account number\n'
49 | + 'as well as read/write privileges are needed to interact with S3, Lambda, and API Gateway. If the user ID and Key do not have these\n'
50 | + 'permissions, there may be unexpected errors when trying to create, invoke, or otherwise interact with AWS. Please ensure the ID and\n'
51 | + 'and Key are safely secured otherwise.\n'
52 | + 'Usage Examples:\n\n '
53 | + code('alana init id111 key2222 account3 ') + '- enters a AWS ID and Key which will verify it against account3 \n '
54 | + code('alana init id4 key5 -b bucket2 -u ') + '- updates the AWS ID and Key and sets the default bucket to bucket2\n '
55 | + code('alana init id6 key7 -d Lambda -u ') + '- updates the AWS ID and Key and sets the default directory to to /Lambda\n '
56 | + '\nSee below for the command line usage\n')
57 | .description('run this to configure access to AWS')
58 | .argument('', 'this is your AWS access key ID')
59 | .argument('', 'this is your AWS secret access key')
60 | .argument('[AWS_ACCOUNT]', 'this is your AWS account number')
61 | .argument('[region]', 'this is your preferred AWS region', defaultRegion)
62 | .option('-r, --role ', 'the AWS Role to be used', defaultRole)
63 | .option('-b, --bucket ', 'the name of the S3 bucket to be used', defaultBucket)
64 | .option('-u, --update', 'set this flag to override and update AWS credentials')
65 | .option('-d, --directory ', 'the directory that files to upload are located in', defaultFolder)
66 | .action(async (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_ACCOUNT, region, options) => {
67 | await init(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_ACCOUNT, region, options.role, options.bucket, options.directory, options.update);
68 | });
69 |
70 |
71 | // only show these if the user has input some credentials
72 | if (hasCredentials) {
73 | program
74 | . addHelpText('before', intro('alanajs\n')
75 | + 'Usage Examples:\n\n '
76 | + code('alana init ') + '- enters a new AWS ID and Key\n '
77 | + code('alana list ') + '- gets a table of all current AWS Lambda functions\n '
78 | + code('alana create hello hello.js file1.js file2.js ') + '- creates a Lambda function named hello where the definition is located in hello.js\n'
79 | + ' with dependencies in file1.js and file2.js\n '
80 | + code('alana update foo codeV2.js ') + '- updates the Lambda function named foo with the code located in codeV2.js\n '
81 | + code('alana delete foo 2 ') + '- delete the Lambda function foo if it has a version 2\n '
82 | + '\nSee below for the command line usage\n');
83 |
84 | program
85 | .command('create')
86 | .addHelpText('before', intro('alanajs\n')
87 | + 'This allows you to interact with Lambda functions, verifying that requirements exist and create them before attempting to create.\n'
88 | + 'Usage Examples:\n\n '
89 | + code('alana create testFunction function.js ') + '- creates a new Lambda function named testFunction from the file function.js\n '
90 | + code('alana create testFunction function.js -d "description" ') + '- creates a new Lambda function named testFunction from the file function.js and adds a description\n '
91 | + code('alana create layer1 function.js ') + '- creates a new Lambda layer named layer1 from the file function.js\n '
92 | + code('alana create -r testrole testfunction function.js ') + '- creates a new Lambda layer named layer1 from the file function.js and give it the permission of testrole\n '
93 | + '\nSee below for the command line usage\n')
94 | .description('zip and create lambda function')
95 | .argument('[funcName]', 'the name of the Lambda function to be create. If not specified, will only verify and create requirements')
96 | .argument('[fileArr...]', 'the file array that needs to be inclided for the Lambda function')
97 | .option('-r, --role [role name]', 'specifying a different AWS role than default specifically for this function')
98 | .option('-b, --bucket ', 'specifying a different S3 bucket name than default')
99 | .option('-d, --description ', 'a description of what the function is supposed to do')
100 | .option('-p, --publish', 'publish a new version of the Lambda function')
101 | .option('-l, --layerName ', 'create AWS lambda layer')
102 | .action(async (funcName, fileArr, options) => {
103 |
104 | // do not create a function if the options don't exist
105 | if (Object.keys(options).length === 0){
106 | if (funcName && fileArr.length === 0) {
107 | console.log(error('File name(s) are required if a function is to be created'));
108 | return;
109 | }
110 | if (!funcName && fileArr.length === 0) {
111 | console.log(error('Function name and file name(s) are required if a function is to be created'));
112 | return;
113 | }
114 | }
115 |
116 | lambdaFunctions.create(funcName, fileArr, options);
117 |
118 | });
119 |
120 | program
121 | .command('list')
122 | .addHelpText('before', intro('alanajs\n')
123 | + 'This will get information about the Lambda functions by listing all or listing the versions\n'
124 | + 'Usage Examples:\n\n '
125 | + code('alana list -F ') + '- lists all the Lambda functions\n '
126 | + code('alana list -f test ') + '- lists all the versions that exist of function test\n '
127 | + '\nSee below for the command line usage\n')
128 | .description('list the various items')
129 | .option('-F, --functions', 'list all the Lambda functions')
130 | .option('-f, --function ', 'list a specific function versions')
131 | .action(async (options) => {
132 | if (options.functions) await lambdaFunctions.list(options);
133 | });
134 |
135 | program
136 | .command('delete')
137 | .addHelpText('before', intro('alanajs\n')
138 | + 'This will allow you to delete a specific Lambda function or a version\n'
139 | + 'Usage Examples:\n\n '
140 | + code('alana delete foo ') + '- deletes the function foo\n '
141 | + code('alana delete bar 5 ') + '- deletes the function bar version 5\n '
142 | + '\nSee below for the command line usage\n')
143 | .description('delete a lambda function')
144 | .argument('')
145 | .argument('[qualifier]')
146 | .action( (funcName, qualifier) => {
147 | lambdaFunctions.delete(funcName, qualifier);
148 | });
149 |
150 | program
151 | .command('update')
152 | .addHelpText('before', intro('alanajs\n')
153 | + 'This will allow you to update a specific Lambda function or a version\n'
154 | + 'Usage Examples:\n\n '
155 | + code('alana update foo bar.js ') + '- updates the function foo with the file bar.js\n '
156 | + code('alana update foo bar.js -d "description" ') + '- updates the function foo with the file bar.js and description\n '
157 | + code('alana update foo bar.js bar2.js folder/bar3.js ') + '- updates the function foo with the file bar.js and dependencies bar2.js and bar3.js\n '
158 | + '\nSee below for the command line usage\n')
159 | .description('update a Lambda function')
160 | .argument('')
161 | .argument('')
162 | .option('-d, --description ', 'a description of what the function is supposed to do')
163 | .option('-p, --publish', 'publish a new version of the Lambda function')
164 | .description('zip and update lambda function')
165 | .action(async (funcName, fileArr, options) => {
166 | await lambdaFunctions.update(funcName, fileArr, options);
167 | });
168 |
169 | program
170 | .command('roles')
171 | .addHelpText('before', intro('alanajs\n')
172 | + 'This will allow you to inteact with AWS IAM roles\n'
173 | + 'Usage Examples:\n\n '
174 | + code('alana roles -l ') + '- list all the roles in AWS IAM\n '
175 | + code('alana roles foobar ') + '- DOES NOT WORK. An interaction method must be used\n '
176 | + code('alana roles -r foobar -c ') + '- creates a new role foobar to interact with Lambda\n '
177 | + code('alana roles --delete foobar ') + '- will only delete the role foobar if it is not the default role\n '
178 | + '\nSee below for the command line usage\n')
179 | .description('interact with AWS Roles')
180 | .argument('[awsRole]', 'the name of the AWS role', defaultRole)
181 | .option('-r, --role ', 'the name of the AWS role')
182 | .option('-c, --create', 'Creates role if it does not exist')
183 | .option('-l, --list', 'List all the roles in AWS')
184 | .option('--delete', 'delete the specified role')
185 | .action(async (awsRole, options) => {
186 | await roles(awsRole, options);
187 | });
188 |
189 | program
190 | .command('buckets')
191 | .addHelpText('before', intro('alanajs\n')
192 | + 'This will allow you to inteact with AWS S3 buckets. S3 buckets are globally namespaced, so there may\n'
193 | + 'be another user that already has the specific named bucket you want to create. Additionally S3 bucket names\n'
194 | + 'will need to be alpha numeric and lowercase only. It will not create if it does not follow this naming convention\n'
195 | + 'Usage Examples:\n\n '
196 | + code('alana buckets -l ') + '- list all the buckets in the user AWS S3\n '
197 | + code('alana buckets -b foobar -c ') + '- creates a new bucket foobar\n '
198 | + code('alana buckets --delete foobar ') + '- will only delete the bucket foobar if it is not the default role\n '
199 | + '\nSee below for the command line usage\n')
200 | .description('interact with AWS S3 buckets')
201 | .argument('[s3bucket]', 'the name of the AWS S3 bucket', defaultBucket)
202 | .option('-b, --bucket ', 'S3 bucket name')
203 | .option('-c, --create', 'Create the bucket if it does not exist')
204 | .option('-l, --list', 'List all the buckets in S3')
205 | .option('--delete', 'delete the specified bucket')
206 | .action(async (s3bucket, options) => {
207 | // console.log(await s3.getBucketList());
208 | await buckets(s3bucket, options);
209 | });
210 |
211 | program
212 | .command('run')
213 | .addHelpText('before', intro('alanajs\n')
214 | + 'This will invoke a function with a potential version specified\n'
215 | + 'Usage Examples:\n\n '
216 | + code('alana invoke foo ') + '- This will invoke the Lambda function foo\n '
217 | + code('alana invoke foo 2 ') + '- This will invoke the Lambda function foo version 2\n '
218 | + '\nSee below for the command line usage\n')
219 | .description('invokes an AWS Lambda function')
220 | .argument('', 'the name of the AWS Lambda function')
221 | .argument('[params...]', 'the parameters being passed into the AWS Lambda function')
222 | .option('-v, --version ', 'the version of the AWS Lambda function being invoked. Must exist')
223 | .action(async (funcName, params, options) => {
224 | lambdaFunctions.invoke(funcName, params, options);
225 | });
226 |
227 | program
228 | .command('createLayer')
229 | .addHelpText('before', intro('alanajs\n')
230 | + 'This allows for creation of Lambda Layer dependencies. By default, the Layers need to be inside the folder\n'
231 | + 'nodejs/node_modules. This will automatically insert the files inside the correct directory structure\n'
232 | + 'Usage Examples:\n\n '
233 | + code('alana createLayer layer1 file1.js ') + '- this will create a Lambda layer named layer1 from file1.js\n '
234 | + '\nSee below for the command line usage\n')
235 | .description('creates an AWS Lambda layer')
236 | .argument('', 'name of the created layer')
237 | .argument('', 'files to be converted into a Lambda layer')
238 | .action(async(layerName, fileArr) => {
239 | await layers.create(layerName, fileArr);
240 | });
241 |
242 | program
243 | .command('addLayerToFunc')
244 | .addHelpText('before', intro('alanajs\n')
245 | + 'This attaches a specific Lambda Layer to a specific Lambda function\n'
246 | + 'Usage Examples:\n\n '
247 | + code('alana addLayerToFunc testFunc -l layer1 ') + '- this will attach the Lambda Layer layer1 to the function testFunc\n '
248 | + '\nSee below for the command line usage\n')
249 | .description('adds AWS Lambda Layer to existant function')
250 | .argument('', 'name of function to append')
251 | .option('-l, --layerName ')
252 | .option('-v, --layerVersion ')
253 | .action(async(funcName, options) => {
254 | await layers.addLayersToFunc(funcName, options);
255 | });
256 |
257 |
258 | program
259 | .command('alias')
260 | .addHelpText('before', intro('alanajs\n')
261 | + 'This lets you interact with Lambda function aliases\n'
262 | + 'Usage Examples:\n\n '
263 | + code('alana alias foo 3 -c test ') + '- this will create an alias named test for the Lambda function foo version 3\n '
264 | + code('alana alias test --delete alias3 ') + '- this will delete the alias alias3 from the Lambda function test\n '
265 | + '\nSee below for the command line usage\n')
266 | .description('Create alias function for each Lamda function')
267 | .argument('', 'name of function to append')
268 | .argument('[version]', 'version of function to point')
269 | .option('-c, --create ', 'Create the alias name if it does not exist')
270 | .option('-u, --update ', 'Update the alias name')
271 | .option('--delete ', 'Delete the alias name')
272 | .action(async(funcName,version, options) => {
273 |
274 | if (Object.keys(options).length > 1) {
275 | console.log(error('Error: Please select 1 option.',options));
276 | return;
277 | }
278 | await aliases(funcName, version, options);
279 | });
280 |
281 | program
282 | .command('api')
283 | .addHelpText('before', intro('alanajs\n')
284 | + 'This lets you interact with API HTTP Gateway\n'
285 | + 'Usage Examples:\n\n '
286 | + code('alana api ') + '- this will list all the APIs in AWS\n '
287 | + code('alana api -c testapi ') + '- this will create an API named testapi\n '
288 | + code('alana api -u testapi -d "this is a test api" ') + '- this will update testapi with a description "this is a test api"\n '
289 | + code('alana api -u testapi -v 5 ') + '- this will update testapi with to the version 5"\n '
290 | + code('alana api --delete testapi ') + '- this will delete the API named testapi\n '
291 | + '\nSee below for the command line usage\n')
292 | .description('interact with the APIs')
293 | .argument('[apiName]', 'name of the api to get information on. Blank for all')
294 | .option('-c, --create', 'create the API named if it doesn\'t exist')
295 | .option('-u, --update', 'updates the API')
296 | .option('-v, --version ', 'specify the version of the api')
297 | .option('-d, --description ', 'the description of the api')
298 | .option('--delete', 'delete the api')
299 | .action(async (apiName, method, route, funcName, options) => {
300 | await apis.api(apiName, method, route, funcName, options);
301 | });
302 |
303 | program
304 | .command('routes')
305 | .addHelpText('before', intro('alanajs\n')
306 | + 'This lets you interact with API HTTP Gateway routes\n'
307 | + 'Usage Examples:\n\n '
308 | + code('alana routes -c GET . testFunc ') + '- this will create a GET method integration to testFunc at the root endpoint\n '
309 | + code('alana routes -c POST valid validateData -d "description" ') + '- this will create a POST method integration to validateDate at the endpoint valid with a description\n '
310 | + code('alana routes -u PUT abc foo ') + '- this will update the PUT method integration at root with the function foo\n '
311 | + code('alana routes --delete GET . ') + '- this will delete the GET method integration at root\n '
312 | + '\nSee below for the command line usage\n')
313 | .description('interact with a route on the API of choice.')
314 | .argument('', 'name of the api')
315 | .argument('[method]', 'type of HTTP request used to invoke')
316 | .argument('[route]', 'route to establish (use "." for root')
317 | .argument('[funcName]', 'the Lambda function that is invoked on the route')
318 | .option('-c, --create', 'create the route specified')
319 | .option('-u, --update', 'update the route specified')
320 | .option('-d, --description ', 'the description of the api')
321 | .option('--delete', 'delete the specified route')
322 | .action(async (apiName, method, route, funcName, options) => {
323 | await apis.routes(apiName, method, route, funcName, options);
324 | });
325 |
326 | program
327 | .command('deploy')
328 | .addHelpText('before', intro('alanajs\n')
329 | + 'This lets you deploy an API gateway. This defaults to autodeploy so any future updates will be reflected\n'
330 | + 'Usage Examples:\n\n '
331 | + code('alana deploy testapi ') + '- this will deploy the API testapi to a randomly generated stage name\n '
332 | + code('alana deploy testapi production -d "live api" ') + '- this will deploy the API testapi to the stage named production with a description\n '
333 | + '\nSee below for the command line usage\n')
334 | .description('deploy the api to a staged name')
335 | .argument('', 'name of the api')
336 | .argument('[stageName]', 'the name of the stage being deployed')
337 | .option('-d, --description ', 'the description of the stage being deployed')
338 | .action(async (apiName, stageName, options) => {
339 | await apis.deploy(apiName, stageName, options);
340 | });
341 | }
342 |
343 | program.parse();
--------------------------------------------------------------------------------
/methods/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/alanajs/914e70cd2ab2ef781a88cbc205a3e670309002bd/methods/.DS_Store
--------------------------------------------------------------------------------
/methods/AWS/deleteGatewayv2.js:
--------------------------------------------------------------------------------
1 | import { ApiGatewayV2Client, DeleteApiCommand, DeleteIntegrationCommand, DeleteRouteCommand } from '@aws-sdk/client-apigatewayv2';
2 | import { AwsParams } from '../util/aws.js';
3 |
4 | const apiGateway = new ApiGatewayV2Client(AwsParams);
5 |
6 | import { starting, error, fail, finished } from '../util/chalkColors.js';
7 |
8 | const api = {};
9 |
10 | api.deleteApi = async (params) => {
11 | console.log(starting(`Deleting the API "${params.Name}"`));
12 | const data = await apiGateway.send(new DeleteApiCommand(params))
13 | .then(data => {
14 | // console.log(data);
15 | console.log(finished(' Finished deleting API\n'));
16 | return data;
17 | })
18 | .catch(err => {
19 | console.log(error('Error in deleting API: ', err.message));
20 | return;
21 | });
22 |
23 | return data;
24 | };
25 |
26 | api.deleteIntegration = async (params) => {
27 | const data = await apiGateway.send(new DeleteIntegrationCommand(params))
28 | .then(data => {
29 | console.log(finished(' Finished deleting integration\n'));
30 | return data;
31 | })
32 | .catch(err => {
33 | console.log(error('Error in deleting integration: ', err.message));
34 | return;
35 | });
36 |
37 | return data;
38 | };
39 |
40 | api.deleteRoute = async (params) => {
41 | const data = await apiGateway.send(new DeleteRouteCommand(params))
42 | .then(data => {
43 | console.log(finished(' Finished deleting route\n'));
44 | return data;
45 | })
46 | .catch(err => {
47 | console.log(error('Error in deleting route: ', err.message));
48 | return;
49 | });
50 |
51 | return data;
52 | };
53 |
54 | export default api;
--------------------------------------------------------------------------------
/methods/AWS/gatewayv2.js:
--------------------------------------------------------------------------------
1 | import { ApiGatewayV2Client, CreateApiCommand, CreateRouteCommand, CreateIntegrationCommand, CreateStageCommand, CreateDeploymentCommand, UpdateApiCommand, DeleteApiCommand } from '@aws-sdk/client-apigatewayv2';
2 | import { AwsAccount, AwsParams, AwsRegion } from '../util/aws.js';
3 |
4 |
5 | const apiGateway = new ApiGatewayV2Client(AwsParams);
6 |
7 | import { starting, error, fail, finished } from '../util/chalkColors.js';
8 |
9 |
10 | const api = {};
11 |
12 | api.createApi = async (params) => {
13 | params.Description ? console.log(starting(`Creating an API named "${params.Name}" with the description "${params.Sescription}"`)) : console.log(starting(`Creating an API named "${params.Name}"`));
14 |
15 | const awsParams = {
16 | Name: params.Name,
17 | ProtocolType: 'HTTP',
18 | };
19 | if (params.Description) awsParams.Description = params.Description;
20 | if (params.Version) awsParams.Version = params.Verion;
21 |
22 | const data = await apiGateway.send(new CreateApiCommand(awsParams))
23 | .then(data => {
24 | console.log(finished(' Finished creating API\n'));
25 | return data;
26 | })
27 | .catch(err => {
28 | console.log(error(' Error in creating API gateway: ', err.message));
29 | return;
30 | });
31 |
32 | return data;
33 | };
34 |
35 | api.createIntegration = async (params) => {
36 | console.log(starting(`Creating an Lambda integration of function "${params.funcName}" to the API "${params.Name}"`));
37 |
38 | const awsParams = {
39 | ApiId: params.ApiId,
40 | IntegrationMethod: 'POST',
41 | IntegrationUri: 'arn:aws:lambda:' + AwsRegion + ':' + AwsAccount + ':function:' + params.funcName,
42 | ConnectionType: 'INTERNET',
43 | IntegrationType: 'AWS_PROXY',
44 | PayloadFormatVersion: '2.0'
45 |
46 | };
47 | const data = await apiGateway.send(new CreateIntegrationCommand(awsParams))
48 | .then(data => {
49 | console.log(finished(' Finished creating integration\n'));
50 | return data;
51 | })
52 | .catch(err => {
53 | console.log(error('Error in creating integration: ', err.message));
54 | return;
55 | });
56 |
57 | return data;
58 | };
59 |
60 | api.createRoute = async (method, route, params) => {
61 | route ? console.log(starting(`Creating a "${method}" request to the route "${route}" in API #${params.Name}"`)) : console.log(starting(`Creating a "${method}" request to the main route of API #${params.Name}"`)) ;
62 |
63 | const awsParams = {
64 | ApiId: params.ApiId,
65 | RouteKey: method.toUpperCase() + ' /' + route,
66 | Target: params.Target
67 | };
68 | const data = await apiGateway.send(new CreateRouteCommand(awsParams))
69 | .then(data => {
70 | console.log(finished(' Finished creating route\n'));
71 | return data;
72 | })
73 | .catch(err => {
74 | console.log(error('Error in creating route: ', err.message));
75 | return;
76 | });
77 |
78 | return data;
79 | };
80 |
81 |
82 | api.createDeployment = async (params) => {
83 | console.log(starting(`Creating a deployment of "${params.Name}"`));
84 | const awsParams = {
85 | ApiId: params.ApiId,
86 | };
87 |
88 | const data = await apiGateway.send(new CreateDeploymentCommand(awsParams))
89 | .then(data => {
90 | console.log(finished(' Finished creating deployment\n'));
91 | return data;
92 | })
93 | .catch(err => {
94 | console.log(error('Error in creating deployment: ', err.message));
95 | return;
96 | });
97 |
98 | return data;
99 | };
100 |
101 | api.createStage = async (params) => {
102 |
103 | console.log(starting(`Creating a staged deployment of "${params.Name}"`));
104 | const awsParams = {
105 | ApiId: params.ApiId,
106 | DeploymentId: params.DeploymentId,
107 | AutoDeploy: true
108 | };
109 |
110 | // it will be the user defined stage name or a random 6 character hex string
111 | params.StageName ? awsParams.StageName = params.StageName : awsParams.StageName = Math.random().toString(16).slice(2, 6);
112 |
113 | const data = await apiGateway.send(new CreateStageCommand(awsParams))
114 | .then(data => {
115 | console.log(finished(' Finished creating staged deployment\n'));
116 | return data;
117 | })
118 | .catch(err => {
119 | console.log(error('Error in creating staged deployment: ', err.message));
120 | return;
121 | });
122 |
123 | return data;
124 | };
125 |
126 | api.updateApi = async (params) => {
127 |
128 | console.log(starting(`Updating the API "${params.Name}"`));
129 | const awsParams = {
130 | ApiId: params.ApiId,
131 | Name: params.Name,
132 | Description: params.Description,
133 | Version: params.Version
134 | };
135 | const data = await apiGateway.send(new UpdateApiCommand(params))
136 | .then(data => {
137 | console.log(finished(' Finished updating API\n'));
138 | return data;
139 | })
140 | .catch(err => {
141 | console.log(error('Error in updating API: ', err.message));
142 | return;
143 | });
144 |
145 | return data;
146 | };
147 |
148 | export default api;
--------------------------------------------------------------------------------
/methods/AWS/getGatewayv2.js:
--------------------------------------------------------------------------------
1 | import { ApiGatewayV2Client, GetApiCommand, GetApisCommand, GetRouteCommand, GetRoutesCommand, GetIntegrationCommand, GetIntegrationsCommand } from '@aws-sdk/client-apigatewayv2';
2 | import { AwsParams } from '../util/aws.js';
3 |
4 | const apiGateway = new ApiGatewayV2Client(AwsParams);
5 |
6 | import { starting, error, fail, finished } from '../util/chalkColors.js';
7 |
8 | const getHTTPApi = {};
9 |
10 | getHTTPApi.getApi = async (params) => {
11 | const data = await apiGateway.send(new GetApiCommand(params))
12 | .then(data => {
13 | // console.log(data);
14 | return data;
15 | })
16 | .catch(err => {
17 | console.log(error('Error in getting API information: ', err.message));
18 | return;
19 | });
20 |
21 | return data;
22 | };
23 |
24 | getHTTPApi.getApis = async () => {
25 | console.log(starting('Getting a list of all APIs'));
26 | const data = await apiGateway.send(new GetApisCommand({}))
27 | .then(data => {
28 | // console.log(data);
29 | console.log(finished(' Finished getting APIs\n'));
30 | return data;
31 | })
32 | .catch(err => {
33 | console.log(error('Error in getting APIs: ', err.message));
34 | return;
35 | });
36 |
37 | return data;
38 | };
39 |
40 | getHTTPApi.getRoute = async (params) => {
41 | const awsParams = {
42 | ApiId: params.ApiId,
43 | RouteId: params.RouteId
44 | };
45 | const data = await apiGateway.send(new GetRouteCommand(awsParams))
46 | .then(data => {
47 | // console.log(data);
48 | return data;
49 | })
50 | .catch(err => {
51 | console.log(error('Error in getting route information: ', err.message));
52 | return;
53 | });
54 |
55 | return data;
56 | };
57 |
58 | getHTTPApi.getRoutes = async (params) => {
59 | console.log(starting('Getting a list of all routes'));
60 | const awsParams = {
61 | ApiId: params.ApiId,
62 | };
63 | const data = await apiGateway.send(new GetRoutesCommand(awsParams))
64 | .then(data => {
65 | // console.log(data);
66 | console.log(finished(' Finished getting routes\n'));
67 | return data;
68 | })
69 | .catch(err => {
70 | console.log(error('Error in getting routes: ', err.message));
71 | return;
72 | });
73 |
74 | return data;
75 | };
76 |
77 | getHTTPApi.getIntegration = async (params) => {
78 | const awsParams = {
79 | ApiId: params.ApiId,
80 | IntegrationId: params.IntegrationId,
81 | };
82 |
83 | const data = await apiGateway.send(new GetIntegrationCommand(awsParams))
84 | .then(data => {
85 | // console.log(data);
86 | return data;
87 | })
88 | .catch(err => {
89 | console.log(error('Error in getting integration: ', err.message));
90 | return;
91 | });
92 |
93 | return data;
94 | };
95 |
96 | getHTTPApi.getIntegrations = async (params) => {
97 | console.log(starting('Getting a list of all integrations'));
98 | const awsParams = {
99 | ApiId: params.ApiId,
100 | IntegrationId: params.IntegrationId,
101 | IntegrationResponseId: params.IntegrationResponseId
102 | };
103 | const data = await apiGateway.send(new GetIntegrationsCommand(awsParams))
104 | .then(data => {
105 | // console.log(data);
106 | console.log(finished(' Finished getting integrations\n'));
107 | return data;
108 | })
109 | .catch(err => {
110 | console.log(error('Error in getting integrations: ', err.message));
111 | return;
112 | });
113 |
114 | return data;
115 | };
116 |
117 | export default getHTTPApi;
--------------------------------------------------------------------------------
/methods/AWS/iam.js:
--------------------------------------------------------------------------------
1 | import { IAMClient, CreateRoleCommand, AttachRolePolicyCommand, ListRolesCommand, DeleteRoleCommand } from '@aws-sdk/client-iam';
2 | import { AwsParams, AwsRole, BasicPolicy, LambdaBasicARN } from '../util/aws.js';
3 |
4 | import { starting, code, error, finished } from '../util/chalkColors.js';
5 |
6 | // create the lambda client
7 | const iamClient = new IAMClient(AwsParams);
8 |
9 | const iam = {};
10 |
11 | iam.getRoleList = async () => {
12 | console.log(starting('Getting a list of the AWS roles'));
13 |
14 | const data = await iamClient.send(new ListRolesCommand({}))
15 | .catch(err => {
16 | console.log(error(`Error while getting AWS roles: ${err.message}`));
17 | return;
18 | });
19 |
20 | return data.Roles;
21 | };
22 |
23 | /**
24 | * @FuncName: verifyRole
25 | * @Description: ASYNC. This will check to see if a role in aws exists
26 | * @input:roleName - a string containing the role name
27 | * @output: boolean -if the role exists
28 | */
29 | iam.verifyRole = async (roleName = AwsRole) => {
30 | console.log(starting(`Verifying the AWS Role named ${roleName}`));
31 |
32 | const data = await iamClient.send(new ListRolesCommand({}))
33 | .catch(err => {
34 | console.log(error(`Error while verifying AWS role: ${err.message}`));
35 | return;
36 | });
37 | // iterate through array and check Name against bucket
38 | for (const el of data.Roles) {
39 | if (el.RoleName === roleName) return true;
40 | }
41 | return false;
42 | };
43 |
44 | /**
45 | * @FuncName: createRole
46 | * @Description: ASYNC. This will create a role in aws for the user to invoke lambda functions
47 | * @input: roleName - a string containing the role name
48 | */
49 | iam.createRole = async (roleName = AwsRole) => {
50 | console.log(starting(`Creating a new AWS Role named ${roleName}`));
51 |
52 | // creating the params for an aws role with no policies attached
53 | const roleParams = {
54 | AssumeRolePolicyDocument: JSON.stringify(BasicPolicy),
55 | RoleName: roleName
56 | };
57 |
58 | await iamClient.send(new CreateRoleCommand(roleParams))
59 | .then(data => {
60 | // console.log(data);
61 | console.log(' Created a new role.');
62 | })
63 | .catch(err => {
64 | console.log(error(`Error while creating a new AWS role: ${err.message}`));
65 | return;
66 | });
67 |
68 |
69 | // create the params to add the lambda basic execution role for global functions
70 | const arnParams = {
71 | RoleName: roleName,
72 | // default policy for lambda functions
73 | PolicyArn: LambdaBasicARN
74 | };
75 | await iamClient.send(new AttachRolePolicyCommand(arnParams))
76 | .then(data => {
77 | // console.log(data)
78 | console.log(' Applied the basic Lambda policy to new role');
79 | console.log(finished(' Finished creating new AWS role with attached basic Lambda functionality policy'));
80 | return;
81 | })
82 | .catch(err => {
83 | console.log(error(`Error while assigning policy to the new AWS role: ${err.message}`));
84 | return;
85 | });
86 |
87 | };
88 |
89 | /**
90 | * @FuncName: deleteRole
91 | * @Description: ASYNC. This will delete a role in AWS
92 | * @input: roleName - a string containing the role name
93 | */
94 |
95 | iam.deleteRole = async (role) => {
96 | const params = {
97 | RoleName: role
98 | };
99 |
100 | const data = await iamClient.send(new DeleteRoleCommand(params))
101 | .catch(err => {
102 | console.log(error(`Error while deleting AWS role : ${err.message}`));
103 | return;
104 | });
105 | return data;
106 | };
107 |
108 | export default iam;
--------------------------------------------------------------------------------
/methods/AWS/lambda.js:
--------------------------------------------------------------------------------
1 | import { LambdaClient,
2 | ListFunctionsCommand,
3 | CreateFunctionCommand,
4 | InvokeCommand,
5 | UpdateFunctionCodeCommand,
6 | DeleteFunctionCommand,
7 | ListVersionsByFunctionCommand,
8 | PublishLayerVersionCommand,
9 | CreateAliasCommand,
10 | UpdateFunctionConfigurationCommand,
11 | UpdateAliasCommand,
12 | DeleteAliasCommand,
13 | GetFunctionConfigurationCommand,
14 | AddPermissionCommand,
15 | RemovePermissionCommand,
16 | GetPolicyCommand } from '@aws-sdk/client-lambda';
17 |
18 | import path from 'path';
19 |
20 | import { AwsRole, AwsParams, AwsBucket, AwsAccount, AwsRegion } from '../util/aws.js';
21 | import { intro, starting, error, fail, finished, code } from '../util/chalkColors.js';
22 |
23 | // create the lambda client
24 | const lambdaClient = new LambdaClient(AwsParams);
25 |
26 | const lambda = {};
27 |
28 | /**
29 | * @FuncName: getFuncList
30 | * @Description: this will send a command to get all the function names
31 | * @output: functionList - an array of function names as strings
32 | *
33 | */
34 | lambda.getFuncList = async () => {
35 | console.log(starting('Getting a list of Lambda functions'));
36 | //parameters for lambda command
37 | const params = { FunctionVersion: 'ALL' };
38 | //sends a command via lambdaClient to list all functions
39 | const data = await lambdaClient.send(new ListFunctionsCommand(params))
40 | .catch(err => {
41 | console.log(error('Error in getting the Lambda Function list: ', err));
42 | });
43 |
44 | if (!data) return;
45 | //parses out the function names from the functionList into a console.table object
46 | const functionList = {};
47 |
48 | // creates a class called lambdaFunc
49 | function lambdaFunc(description, version, lastModified) {
50 | this.Description = description;
51 | this.Version = version;
52 | this.LastModified = lastModified;
53 | }
54 |
55 | data.Functions.map((el) => {
56 | functionList[el.FunctionName] = new lambdaFunc(el.Description, el.Version, el.LastModified.toLocaleString());
57 | });
58 | // res.locals.functionList = functionList;
59 | return functionList;
60 | };
61 |
62 | lambda.getFuncVersionList = async (funcName) => {
63 | console.log(starting(`Getting a list of versions of Lambda function "${funcName}"`));
64 | const params = {FunctionName: funcName};
65 | const data = await lambdaClient.send(new ListVersionsByFunctionCommand(params))
66 | .catch(err => {
67 | console.log(error('Error in getting the Lambda Function versions: ', err.message));
68 | });
69 | if (!data) return;
70 | console.log('this is funcversionlist data',data);
71 | // NOT FORMATTED TO A TABLE YET
72 | return data;
73 | };
74 |
75 | /**
76 | * @FuncName: invoke
77 | * @Description: this will invoke the function specified in the parameters
78 | * @input:FuncName - the name of the function
79 | * @params - the parameters for the function
80 | * @output: the invocation response
81 | */
82 | lambda.invoke = (funcName, params, options = {}) => {
83 | // destructure and set defaults to options if not included;
84 | const {bucket = AwsBucket, description = undefined, publish = false} = options;
85 | options.version ? console.log(starting(`Invoking the function "${funcName}" with the Qualifier "${options.version}"`)) : console.log(starting(`Invoking the function "${funcName}"`));
86 | //input parameters for running the aws lambda function
87 | const lambdaParams = {
88 | //needed function name
89 | FunctionName: funcName,
90 |
91 | // pass in arguments for the lambda function (input payload)
92 | Payload: JSON.stringify(params),
93 |
94 | //default options that we may not need to change
95 | InvocationType: 'RequestResponse',
96 | LogType: 'Tail',
97 | };
98 | if (options.version) lambdaParams.Qualifier = options.version;
99 |
100 | // invokecommand is a class that lets lambdaclient know that we want to run the function that is specified in the params
101 | lambdaClient.send(new InvokeCommand(lambdaParams))
102 | .then(data => {
103 | // console.log(data);
104 |
105 | //This will output the invocation data log into a readable string
106 | // console.log(Buffer.from(data.LogResult,'base64').toString('ascii'));
107 |
108 | // lambda client returns data.payload which is utf8 and needs to be decoded and parsed
109 | const response = JSON.parse(new TextDecoder('utf-8').decode(data.Payload));
110 | console.log(response);
111 | return response;
112 | })
113 | .catch(err => {
114 | console.log(error('Error in invoke: ', err.message));
115 | return err;
116 | });
117 | };
118 |
119 | /**
120 | * @FuncName: createFunction
121 | * @Description: this will create the function based on the file given in the S3 bucket
122 | * @input:funcName - the name of the function, user input, :outputZip - the file name of the zip file
123 | *
124 | */
125 | lambda.createFunction = async(outputZip, funcName, options = {}) => {
126 |
127 | // destructure and set defaults to options if not included;
128 | const {role = AwsRole, bucket = AwsBucket, description = undefined, layerArr = null, publish = false} = options;
129 |
130 | console.log(starting(`Creating the function "${funcName}" from the output file "${outputZip}" found in the S3 Bucket "${bucket}"`));
131 |
132 | // parameters for lambda command
133 | const params = {
134 | Code: {S3Bucket: bucket, S3Key: outputZip },
135 | FunctionName: funcName,
136 | Runtime: 'nodejs14.x',
137 | Handler: 'index.handler',
138 | Role: `arn:aws:iam::${AwsAccount}:role/${role}`,
139 | Description: description,
140 | Publish: publish,
141 | Layers: layerArr
142 | };
143 |
144 | const layerConfig = [];
145 | if(layerArr){
146 |
147 | for (let i = 0; i < layerArr.length; i++){
148 | const layerName = layerArr[i].layerName;
149 | const layerVersion = layerArr[i].layerVersion;
150 | layerConfig.push(`arn:aws:lambda:${AwsRegion}:${AwsAccount}:layer:${layerName}:${layerVersion}`);
151 | }
152 | if(layerConfig.length > 0) params.Layers = layerConfig;
153 | }
154 |
155 | //sends a command via lambdaClient to create a function
156 |
157 | return await lambdaClient.send(new CreateFunctionCommand(params))
158 | .then(data => {
159 | console.log(finished(' Finished creating the function in Lambda.\n'));
160 | return data;
161 | })
162 | .catch(err => {
163 | console.log(error('\n Error in lambda CreateFunctionCommand: ', err.message));
164 | return err;
165 | });
166 | };
167 |
168 | /**
169 | * @FuncName: updateFunction
170 | * @Description: this will update the function FunctionName based on the file given in the S3 bucket
171 | * @input:funcName - the name of the function, user input :outputZip - the file name of the zip file
172 | */
173 |
174 | lambda.updateFunction = async (outputZip, funcName, options = {}) => {
175 | // destructure options
176 | const {bucket = AwsBucket, publish = true} = options;
177 |
178 | console.log(' using lambdaController.updateFunction');
179 |
180 | // params for lambda command
181 | const params = {
182 | FunctionName: funcName,
183 | Publish: publish,
184 | S3Bucket: bucket,
185 | S3Key: path.basename(outputZip),
186 | };
187 |
188 | // send the update function command
189 | const data = await lambdaClient.send(new UpdateFunctionCodeCommand(params))
190 | .then(data => {
191 | // console.log(data);
192 | return data;
193 | })
194 | .catch(err => {
195 | console.log(error('Error in lambda updateFunctionCode:', err.message));
196 | return err;
197 | });
198 | return data;
199 | };
200 |
201 | /**
202 | * @FuncName: deleteFunction
203 | * @Description: this will delete the function with the specified name
204 | * @input: funcName - the name of the function, user input
205 | */
206 | lambda.deleteFunction = async (funcName, qualifier) => {
207 | qualifier ? console.log(starting(`Deleting the function "${funcName}" with the Qualifier "${qualifier}"`)) : console.log(starting(`Deleting the function "${funcName}"`));
208 |
209 | // parameters for lambda command
210 | const params = {
211 | FunctionName: funcName,
212 | };
213 |
214 | //qualifier: optional version to delete
215 | if(qualifier) params.Qualifier = qualifier;
216 |
217 | return await lambdaClient.send(new DeleteFunctionCommand(params))
218 | .then(data => {
219 | // console.log(data);
220 | return data;
221 | })
222 | .catch(err => {
223 | console.log(error('Error in lambda DeleteFunctionCommand: ', err.message));
224 | return err;
225 | });
226 | };
227 |
228 |
229 |
230 | /**
231 | * @FuncName: createLambdaLayer
232 | * @Description: this will create a lambda layer with the specified name and code
233 | * @Input: layername - string that contains layername, :outputZip - file name of the zip file
234 | */
235 | lambda.createLambdaLayer = async (layerName, outputZip) => {
236 | console.log(' using lambda.addLambdaLayers');
237 |
238 | const params = {
239 | Content: {S3Bucket: AwsBucket, S3Key: outputZip},
240 | LayerName: layerName
241 | };
242 |
243 | return await lambdaClient.send(new PublishLayerVersionCommand(params))
244 | .then(data => {
245 | return data;
246 | })
247 | .catch(err => {
248 | console.log('Error in lambda PublishLayerVersionCommand: ', err);
249 | });
250 | };
251 |
252 | /**
253 | * @FuncName: addLayerToFunc
254 | * @Description: this will add AWS lambda layers to specified function
255 | * @input: funcName - string that contains name of function,
256 | */
257 | lambda.addLayerToFunc = async (funcName, layerArr) => {
258 | console.log('using lambda.addLayerToFunc');
259 |
260 | console.log('the layerArr is ', layerArr);
261 |
262 | const params = {
263 | FunctionName : funcName
264 | };
265 |
266 | const layerConfig = [];
267 | if(layerArr){
268 |
269 | for (let i = 0; i < layerArr.length; i++){
270 | const layerName = layerArr[i].layerName;
271 | const layerVersion = layerArr[i].layerVersion;
272 | layerConfig.push(`arn:aws:lambda:${AwsRegion}:${AwsAccount}:layer:${layerName}:${layerVersion}`);
273 | }
274 | if(layerConfig.length > 0) params.Layers = layerConfig;
275 | console.log(params.Layers);
276 | }
277 |
278 | return await lambdaClient.send(new UpdateFunctionConfigurationCommand(params))
279 | .then(data => {
280 | return data;
281 | })
282 | .catch(err => {
283 | console.log('Error in lambda updateFunctionConfigurationCommand: ', err);
284 | });
285 | };
286 |
287 | //FunctionVersion: Func Version that alias invoked
288 | //name: Name of the Alias
289 | lambda.createAlias = async(funcName, version, aliasName = 'aliasName') => {
290 |
291 | // params for lambda command
292 | const params = {
293 | FunctionName: funcName,
294 | FunctionVersion : version,
295 | Name: aliasName
296 | };
297 |
298 | // send the new alias
299 | return await lambdaClient.send(new CreateAliasCommand(params))
300 | .then(data => {
301 | // console.log(data);
302 | return data;
303 | })
304 | .catch(err => {
305 | console.log(error('Error in lambda createAliasCommand:', err.message));
306 | return err;
307 | });
308 | };
309 |
310 | lambda.updateAlias = async(funcName, version, aliasName) => {
311 |
312 | // params for lambda command
313 | const params = {
314 | FunctionName: funcName,
315 | FunctionVersion : version,
316 | Name: aliasName
317 | };
318 |
319 | // send the new alias
320 | return await lambdaClient.send(new UpdateAliasCommand(params))
321 | .then(data => {
322 | // console.log(data);
323 | return data;
324 | })
325 | .catch(err => {
326 | console.log(error('Error in lambda updateAliasCommand:', err.message));
327 | return err;
328 | });
329 | };
330 |
331 | lambda.deleteAlias = async(funcName, aliasName = 'aliasName') => {
332 |
333 | // params for lambda command
334 | const params = {
335 | FunctionName: funcName,
336 | Name: aliasName
337 | };
338 |
339 | // send the new alias
340 | return await lambdaClient.send(new DeleteAliasCommand(params))
341 | .then(data => {
342 | // console.log(data);
343 | return data;
344 | })
345 | .catch(err => {
346 | console.log(error('Error in lambda updateAliasCommand:', err.message));
347 | return err;
348 | });
349 | };
350 |
351 | lambda.getFuncConfig = async (funcName) => {
352 | const params = {
353 | FunctionName: funcName
354 | };
355 |
356 | await lambdaClient.send(new GetFunctionConfigurationCommand(params))
357 | .then(data => {
358 | console.log(data);
359 | return data;
360 | })
361 | .catch(err => {
362 | console.log('Error in lambda getFunctionConfigurationCommand: ', err.message);
363 | });
364 | };
365 |
366 | lambda.addPermission = async (funcName, apiId, route) => {
367 | console.log(starting(`Adding API permissions to "${funcName}"`));
368 | const params = {
369 | StatementId: funcName + Date.now().toString(),
370 | Action: 'lambda:InvokeFunction',
371 | FunctionName: `arn:aws:lambda:${AwsRegion}:${AwsAccount}:function:${funcName}`,
372 | Principal: 'apigateway.amazonaws.com',
373 | SourceArn: `arn:aws:execute-api:${AwsRegion}:${AwsAccount}:${apiId}/*/*/`
374 | };
375 |
376 | if (route) params.SourceArn = params.SourceArn + `${route}`;
377 |
378 | const data = await lambdaClient.send(new AddPermissionCommand(params))
379 | .then(data => {
380 | // console.log(data);
381 | console.log(finished(' Finished adding permissions\n'));
382 | return data;
383 | })
384 | .catch(err => {
385 | console.log(error('Error in adding permissions: ', err.message));
386 | return;
387 | });
388 |
389 | return data;
390 | };
391 |
392 | lambda.removePermission = async (funcName, statementId) => {
393 | console.log(starting(`Removing API permissions to "${funcName}"`));
394 | const params = {
395 | StatementId: statementId,
396 | FunctionName: `arn:aws:lambda:${AwsRegion}:${AwsAccount}:function:${funcName}`,
397 | };
398 |
399 | const data = await lambdaClient.send(new RemovePermissionCommand(params))
400 | .then(data => {
401 | // console.log(data);
402 | console.log(finished(' Finished removing permissions\n'));
403 | return data;
404 | })
405 | .catch(err => {
406 | console.log(error('Error in removing permissions: ', err.message));
407 | return;
408 | });
409 |
410 | return data;
411 | };
412 |
413 | lambda.getPolicy = async (funcName, qualifier = undefined) => {
414 | console.log(starting(`Getting permission policy of "${funcName}"`));
415 | const params = {
416 | FunctionName: funcName,
417 | Qualifier: qualifier
418 | };
419 |
420 | const data = await lambdaClient.send(new GetPolicyCommand(params))
421 | .then(data => {
422 | // console.log(data);
423 | console.log(finished(' Finished getting permission policy\n'));
424 | return data;
425 | })
426 | .catch(err => {
427 | console.log(error('Error in getting permission policy: ', err.message));
428 | return;
429 | });
430 |
431 | return data;
432 | };
433 |
434 | export default lambda;
--------------------------------------------------------------------------------
/methods/AWS/s3.js:
--------------------------------------------------------------------------------
1 | import { S3Client, PutObjectCommand, CreateBucketCommand, GetBucketAclCommand, ListBucketsCommand, DeleteBucketCommand } from '@aws-sdk/client-s3';
2 | import path from 'path';
3 | import fs from 'fs';
4 |
5 | import {AwsParams, AwsBucket} from '../util/aws.js';
6 | import { starting, code, error, finished } from '../util/chalkColors.js';
7 |
8 | // create the s3 client
9 | const s3Client = new S3Client(AwsParams);
10 |
11 | const s3 = {};
12 |
13 | /**
14 | * ASYNC Get a list of all the S3 buckets under the user's account
15 | * @returns (array) A list of all S3 buckets
16 | */
17 | s3.getBucketList = async () => {
18 | console.log(starting('Getting the list of S3 buckets'));
19 |
20 | const data = await s3Client.send(new ListBucketsCommand({}))
21 | .catch(err => {
22 | console.log(error(`Error while getting S3 bucket list: ${err.message}`));
23 | return;
24 | });
25 | return data.Buckets;
26 | };
27 |
28 | /**
29 | * ASYNC. Verifies whether or not a bucket named bucketName exists in the user's S3 namespace
30 | * @param {*} bucketName (string) a string containing the bucket name, or the default bucket name
31 | * @returns (boolean) whether or not the bucket specified in input exists in S3
32 | */
33 | s3.verifyBucket = async (bucketName = AwsBucket) => {
34 | console.log(starting(`Verifying the AWS S3 bucket named "${bucketName}"`));
35 |
36 | // get a list of buckets
37 | const data = await s3Client.send(new ListBucketsCommand({}))
38 | .catch(err => {
39 | console.log(error(`Error while getting S3 bucket list: ${err.message}`));
40 | return;
41 | });
42 |
43 | // iterate through array and check Name against bucket
44 | for (const el of data.Buckets) {
45 | if (el.Name === bucketName) return true;
46 | }
47 | return false;
48 | };
49 |
50 | /**
51 | * ASYNC. This creates an S3 bucket named bucketName
52 | * @param {*} bucketName - (string) The name of the bucket to be created
53 | * @returns (various) undefined if there's an error. The AWS response object if command is sent properly.
54 |
55 | */
56 | s3.createBucket = async (bucketName = AwsBucket) => {
57 | console.log(starting(`Creating an AWS S3 bucket named "${bucketName}"`));
58 |
59 | // params needed to create a s3 bucket
60 | const params = {
61 | // bucket name
62 | Bucket: bucketName,
63 | };
64 |
65 | // create the bucket
66 | // Amazon S3 bucket names must be unique globally. If you get the "Bucket name already exists" or "BucketAlreadyExists" error,
67 | // then you must use a different bucket name to create the bucket. These error messages indicate that another AWS account owns a bucket with the same name.
68 | const response = await s3Client.send(new CreateBucketCommand(params))
69 | .then(data => {
70 | // do something with data
71 | console.log(finished(' Finished creating a new S3 bucket.\n'));
72 | // console.log(data);
73 | return data;
74 | })
75 | .catch(err => {
76 | console.log(error(`There's an error with creating an S3 bucket: ${err.message}`));
77 | if (err.message === 'BucketAlreadyExists') {
78 | console.log(error('Amazon S3 bucket names must be unique globally. If you get the "Bucket name already exists" or "BucketAlreadyExists" error, then you must use a different bucket name to create the bucket. These error messages indicate that another AWS account owns a bucket with the same name.'));
79 | }
80 | return;
81 | });
82 | return response;
83 | };
84 |
85 |
86 | /**
87 | * ASYNC. This sends a file outputZip to the S3 bucket bucketName
88 | * @param {*} outputZip - (string) zip file name that will be sent to S3
89 | * @param {*} bucketName - (string) bucket where the zip file is being sent to
90 | * @returns (various) undefined if there's an error. OutputZip if command is sent properly.
91 | */
92 | s3.sendFile = async (outputZip, bucketName = AwsBucket) => {
93 | console.log(starting(`Sending the file "${outputZip}" to the AWS S3 Bucket "${bucketName}"`));
94 | // creates a file stream of the zip file
95 | const fileStream = fs.createReadStream(outputZip);
96 |
97 | const params = {
98 | // s3 bucket
99 | Bucket: bucketName,
100 | // Add the required 'Key' parameter using the 'path' module.
101 | Key: path.basename(outputZip),
102 | // Add the required 'Body' parameter
103 | Body: fileStream,
104 | };
105 | const data = await s3Client.send(new PutObjectCommand(params))
106 | .then(data => {
107 | // console.log(data);
108 | console.log(finished(' Finished sending file.\n'));
109 | return outputZip;
110 | })
111 | .catch(err => {
112 | // console.log(err);
113 | console.log(error(`Error sending file to the S3 bucket : ${err.message}`));
114 | return;
115 | });
116 | return data;
117 | };
118 |
119 |
120 | /**
121 | * ASYNC. This will send a command to AWS S3 to delete a bucket
122 | * @param {*} bucketName - (string) The name of the bucket to be deleted
123 | * @returns (object) the AWS metadata from the command
124 | */
125 | s3.deleteBucket = async (bucketName) => {
126 | console.log(starting(`Deleting the AWS S3 bucket named "${bucketName}"`));
127 | const params = {
128 | Bucket: bucketName
129 | };
130 |
131 | const data = await s3Client.send(new DeleteBucketCommand(params))
132 | .then(data => {
133 | // console.log(data);
134 | console.log(finished(' Finished deleting the bucket.\n'));
135 | return data;
136 | })
137 | .catch(err => {
138 | console.log(error(`Problem with deleting S3 bucket : ${err.message}`));
139 | return;
140 | });
141 | return data;
142 | };
143 |
144 | export default s3;
--------------------------------------------------------------------------------
/methods/commands/aliases.js:
--------------------------------------------------------------------------------
1 | import lambda from '../AWS/lambda.js';
2 |
3 | import { intro, starting, error, fail, finished, code } from '../util/chalkColors.js';
4 |
5 | const aliases = async (funcName, version, options) => {
6 | if (options.create){
7 | const aliasName = options.create;
8 | console.log(starting('Sending request to AWS Lambda...'));
9 | const response = await lambda.createAlias(funcName, version, aliasName);
10 | if (response.$metadata.httpStatusCode < 300) console.log(finished('Request complete: Alias created'));
11 | }
12 |
13 | else if (options.update){
14 | const aliasName = options.update;
15 | console.log(starting('Sending request to AWS Lambda...'));
16 | const response = await lambda.updateAlias(funcName, version, aliasName);
17 | if (response.$metadata.httpStatusCode < 300) console.log(finished('Request complete: Alias updated'));
18 | }
19 |
20 | else if (options.delete){
21 | const aliasName = options.delete;
22 | console.log(starting('Sending request to AWS Lambda...'));
23 | const response = await lambda.deleteAlias(funcName, aliasName);
24 | if (response.$metadata.httpStatusCode < 300) console.log(finished('Request complete: Alias deleted'));
25 | }
26 | };
27 |
28 |
29 | export default aliases;
--------------------------------------------------------------------------------
/methods/commands/apis.js:
--------------------------------------------------------------------------------
1 | import api, {default as awsApi } from '../AWS/gatewayv2.js';
2 | import {default as getApi } from '../AWS/getGatewayv2.js';
3 | import {default as deleteApi } from '../AWS/deleteGatewayv2.js';
4 |
5 | import lambda from '../AWS/lambda.js';
6 | import { AwsRegion, AwsAccount } from '../util/aws.js';
7 |
8 | //NEED TO ADD THIS TO THE REST OF THE PRODUCT
9 |
10 | import { starting, code, error, finished } from '../util/chalkColors.js';
11 | import { verifyFunction } from '../util/verifyAWS.js';
12 |
13 | const methods = ['ANY', 'GET', 'POST', 'PUT', 'PATCH', 'HEAD', 'DELETE', 'OPTIONS'];
14 |
15 | const verifyMethod = (method) => {
16 | method = method.toUpperCase();
17 | if (!methods.includes(method)) {
18 | console.log(error('The request method specified is an invalid HTTP request. The only valid requests are: '));
19 | console.log(' ', code(methods));
20 | return false;
21 | }
22 | return method;
23 | };
24 |
25 | const getApiId = async (apiName) => {
26 | const getApisResponse = await getApi.getApis();
27 |
28 | // get the API ID from the name
29 | for (const item of getApisResponse.Items) {
30 | if (item.Name === apiName) {
31 | return item.ApiId;
32 | }
33 | }
34 | console.log(error('No matching API name.'));
35 | return false;
36 | };
37 | const apis = {};
38 |
39 | apis.routes = async(apiName, method, route, funcName, options) => {
40 | if (!options) await apis.getRoutes(apiName);
41 |
42 | if (funcName) {
43 | const validFunction = await verifyFunction(funcName);
44 | if (!validFunction) return;
45 | }
46 | if (options.create) {
47 | await apis.createRoute(apiName, method, route, funcName, options);
48 | return;
49 | }
50 | else if (options.update) {
51 | await apis.deleteRoute(apiName, method, route);
52 | await apis.createRoute(apiName, method, route, funcName, options);
53 | return;
54 | }
55 | else if (options.delete) {
56 | await apis.deleteRoute(apiName, method, route);
57 | return;
58 | }
59 | };
60 |
61 | apis.createApi = async (apiName, options) => {
62 | const params = {
63 | Name: apiName
64 | };
65 |
66 | // add on optional params
67 | if (options.description) params.description = options.description;
68 |
69 | return await awsApi.createApi(params);
70 | };
71 |
72 | apis.api = async (apiName, options) => {
73 | if (!apiName) {
74 | const apis = await getApi.getApis();
75 | for (const item of apis.Items) {
76 | console.log('Name:', item.Name);
77 | if (item.Version) console.log('Version:', item.Version);
78 | console.log('Created Date:', item.CreatedDate);
79 | console.log('Description:', item.Description);
80 | console.log('API Endpoint:', item.ApiEndpoint);
81 | console.log('\n');
82 | }
83 | return;
84 | }
85 |
86 | const params = {
87 | Name: apiName,
88 | };
89 | if (options.description) params.Description = options.description;
90 | if (options.version) params.Version = options.version;
91 |
92 | if (options.create) {
93 | await apis.createApi(apiName, params);
94 | return;
95 | }
96 | const ApiId = await getApiId(apiName);
97 | if (!ApiId) return;
98 | params.ApiId = ApiId;
99 |
100 | if (options.update) {
101 | await api.updateApi(params);
102 | return;
103 | }
104 | if (options.delete) {
105 | await deleteApi.deleteApi(params);
106 | return;
107 | }
108 | else {
109 | const apiInformation = await getApi.getApi(params);
110 | console.log(apiInformation);
111 | }
112 | };
113 | apis.createRoute = async (apiName, method, route, funcName, options) => {
114 | // verify that method type is accurate
115 | method = verifyMethod(method);
116 | if (!method) return;
117 |
118 | // verify route. Set route to main route if it's '.'
119 | if (route === '*') {
120 | console.log(error('Invalid route'));
121 | return;
122 | }
123 | if (route === '.') route = '';
124 |
125 | const outputParams = {};
126 |
127 | const params = {
128 | Name: apiName,
129 | funcName: funcName
130 | };
131 |
132 | params.ApiId = await getApiId(apiName);
133 | if (!params.ApiId) return;
134 |
135 | // create the integration
136 | const createIntegrationResponse = await awsApi.createIntegration(params);
137 | if (!createIntegrationResponse) return;
138 | else {
139 | // add integration ID to params
140 | params.IntegrationId = createIntegrationResponse.IntegrationId;
141 | params.Target = 'integrations/' + createIntegrationResponse.IntegrationId;
142 | }
143 | // create the method
144 | const createRouteResponse = await awsApi.createRoute(method, route, params);
145 | if (!createRouteResponse) return;
146 |
147 | // adds the permission
148 | const addPermissionResponse = await lambda.addPermission(funcName, params.ApiId, route);
149 | if (!addPermissionResponse) return;
150 |
151 | //
152 | route ? console.log(`A ${method} request to ${route} has been created.`) : console.log(`A ${method} request to root has been created.`);
153 | };
154 |
155 |
156 | apis.getRoutes = async (apiName) => {
157 | const output = [];
158 | const params = {};
159 |
160 | params.ApiId = await getApiId(apiName);
161 | if (!params.ApiId) return;
162 |
163 | // get all the routes
164 | const getRoutesResponse = await getApi.getRoutes(params);
165 |
166 | console.log(getRoutesResponse);
167 | // iterate over the routes
168 | for (const item of getRoutesResponse.Items) {
169 | // get the itegration IDs
170 | const integrationParams = {
171 | ApiId: params.ApiId,
172 | IntegrationId: item.Target.slice(13)
173 | };
174 |
175 | // get the information from the integration
176 | const getIntegrationResponse = await getApi.getIntegration(integrationParams);
177 |
178 | // parse out the info to respond into an array for a console table
179 | const apiRoute = {};
180 | const routeBreak = item.RouteKey.indexOf('/');
181 | apiRoute.Method = item.RouteKey.slice(0, routeBreak - 1);
182 | apiRoute.Route = item.RouteKey.slice(routeBreak + 1);
183 | const integrationUri = getIntegrationResponse.IntegrationUri;
184 | const functinBreak = integrationUri.indexOf('function:') + 9;
185 | apiRoute.FunctionName = integrationUri.slice(functinBreak);
186 |
187 | output.push(apiRoute);
188 | }
189 | // output the routes
190 | console.table(output);
191 | };
192 |
193 |
194 | apis.deleteRoute = async (apiName, method, route) => {
195 | // verify that method type is accurate
196 | method = verifyMethod(method);
197 | if (!method) return;
198 |
199 | // get api id
200 | const apiId = await getApiId(apiName);
201 | if (!apiId) return;
202 |
203 | const params = {
204 | ApiId: apiId
205 | };
206 |
207 | // get methods and then the specific integration
208 | const routeKey = method.toUpperCase() + ' /' + route;
209 | const routes = await getApi.getRoutes(params);
210 |
211 | for (const item of routes.Items) {
212 | if (item.RouteKey === routeKey) {
213 | console.log(' Found matching integration\n');
214 | params.IntegrationId = item.Target.slice(13);
215 | params.RouteId = item.RouteId;
216 | break;
217 | }
218 | }
219 |
220 | // get the information from the integration
221 | const integration = await getApi.getIntegration(params);
222 | const functinBreak = integration.IntegrationUri.indexOf('function:') + 9;
223 | const functionName = integration.IntegrationUri.slice(functinBreak);
224 |
225 | // delete the route and integration
226 | await deleteApi.deleteRoute(params);
227 | await deleteApi.deleteIntegration(params);
228 |
229 | // form the comparison permission
230 | if (route === '.') route = '';
231 | let sourceArn = `arn:aws:execute-api:${AwsRegion}:${AwsAccount}:${apiId}/*/*/`;
232 | if (route) sourceArn = sourceArn + `${route}`;
233 |
234 | // remove the permissions from the function
235 | let {Policy} = await lambda.getPolicy(functionName);
236 | Policy = JSON.parse(Policy);
237 |
238 | let statementId = '';
239 | for (const statement of Policy.Statement) {
240 | if(sourceArn === statement.Condition.ArnLike['AWS:SourceArn']) {
241 | statementId = statement.Sid;
242 | break;
243 | }
244 | }
245 | await lambda.removePermission(functionName, statementId);
246 | return;
247 | };
248 |
249 | apis.deploy = async (apiName, stageName, options) => {
250 | const outputParams = {};
251 |
252 | const params = {
253 | Name: apiName,
254 | StageName: stageName
255 | };
256 |
257 | if (options.description) params.Description = options.description;
258 |
259 | // get api id
260 | params.ApiId = await getApiId(apiName);
261 | if (!params.ApiId) return;
262 |
263 | // add a deployment
264 | const createDeploymentResponse = await awsApi.createDeployment(params);
265 | if (!createDeploymentResponse) return;
266 | else {
267 | params.DeploymentId = createDeploymentResponse.DeploymentId;
268 | }
269 |
270 | // create a stage
271 | const createStageResponse = await awsApi.createStage(params);
272 | if (!createStageResponse) return;
273 | else {
274 | outputParams.StageName = createStageResponse.StageName;
275 | }
276 |
277 | // get the apiData
278 | const getApiResponse = await getApi.getApi(params);
279 | outputParams.ApiEndpoint = getApiResponse.ApiEndpoint;
280 |
281 | console.log(finished(`The API "${apiName}" has been deloyed. See: \n `));
282 | console.log(code(` ${outputParams.ApiEndpoint}/${outputParams.StageName}/\n`));
283 |
284 | };
285 |
286 | export default apis;
--------------------------------------------------------------------------------
/methods/commands/buckets.js:
--------------------------------------------------------------------------------
1 | import s3 from '../AWS/s3.js';
2 | import { AwsBucket } from '../util/aws.js';
3 | import { verifyBucket } from '../util/verifyAWS.js';
4 | import { intro, starting, error, fail, finished, code } from '../util/chalkColors.js';
5 |
6 | const buckets = async (s3bucket, options) => {
7 | // console.log(await s3.getBucketList());
8 | if (options.delete) {
9 | if (s3bucket === AwsBucket) {
10 | console.log(fail('Cannot delete default bucket. Change default bucket before deleting'));
11 | return;
12 | }
13 | let data;
14 | if (options.bucket) data = await s3.deleteBucket(options.bucket);
15 | if (!options.bucket && s3bucket !== AwsBucket) data = await s3.deleteBucket(s3bucket);
16 | if (data) console.log(finished(` S3 bucket '${options.bucket || s3bucket}' deleted.`));
17 | return;
18 | }
19 | if (options.list) console.log(await s3.getBucketList());
20 | if (options.bucket) await verifyBucket(options.bucket, options.create);
21 | if (!options.bucket && s3bucket !== AwsBucket) await verifyBucket(s3bucket, options.create);
22 | };
23 |
24 | export default buckets;
--------------------------------------------------------------------------------
/methods/commands/functions.js:
--------------------------------------------------------------------------------
1 | import {verifyRole, verifyBucket} from '../util/verifyAWS.js';
2 |
3 | import lambda from '../AWS/lambda.js';
4 | import s3 from '../AWS/s3.js';
5 |
6 | import {AwsBucket, AwsRole } from '../util/aws.js';
7 | import archiver from '../util/archiver.js';
8 |
9 | import { intro, starting, error, fail, finished, code } from '../util/chalkColors.js';
10 |
11 | const lambdaFunctions = {};
12 |
13 | lambdaFunctions.create = async (funcName, fileArr, options = {}) => {
14 | options.role ? await verifyRole((options.role || funcName || AwsRole), true) : await verifyRole(AwsRole, true);
15 | options.bucket ? await verifyBucket(options.bucket, true) : await verifyBucket(AwsBucket, true);
16 |
17 | let created;
18 | // alana create function1 functionfile1 -l layer1 -f layerfile1 layerfile2
19 | console.log(starting('Compressing files...'));
20 | const outputZip = await archiver.zipFiles(fileArr);
21 | console.log(starting('Sending files to s3...'));
22 | const response = await s3.sendFile(outputZip, options.bucket);
23 | console.log(starting('Sending files to AWS Lambda...'));
24 | if (response) created = await lambda.createFunction(outputZip, funcName, options);
25 | // console.log('response',response);
26 | if (created.$metadata.httpStatusCode < 300) console.log(finished('Request completed: AWS Lambda function created'));
27 | };
28 |
29 | lambdaFunctions.list = async (options) => {
30 | if (options.function) {
31 | lambda.getFuncVersionList(options.function);
32 | return;
33 | }
34 | const list = await lambda.getFuncList();
35 | console.table(list);
36 | };
37 |
38 | lambdaFunctions.delete = async (funcName, qualifier) => {
39 | const response = await lambda.deleteFunction(funcName, qualifier);
40 | if (response.$metadata.httpStatusCode < 300) console.log(finished('Request complete: AWS Lambda function deleted'));
41 | };
42 |
43 | lambdaFunctions.update = async (funcName, fileArr, options) => {
44 | // const outputZip = `${fileArr}.zip`;
45 | let updated;
46 | console.log(starting('Compressing updated files...'));
47 | const outputZip = await archiver.zipFiles(fileArr);
48 | // await archiver.zipFiles(fileArr);
49 | console.log(starting('Sending files to s3...'));
50 | const response = await s3.sendFile(outputZip);
51 | console.log(starting('Sending files to AWS Lambda...'));
52 | if (response) updated = await lambda.updateFunction(outputZip, funcName, options);
53 | if (updated.$metadata.httpStatusCode < 300) console.log(finished('Request complete: AWS Lambda function updated'));
54 | };
55 |
56 | lambdaFunctions.invoke = async (funcName, params, options) => {
57 | lambda.invoke(funcName, params, options);
58 | console.log(finished('Request complete: Lambda function invoked'));
59 | };
60 |
61 | export default lambdaFunctions;
--------------------------------------------------------------------------------
/methods/commands/layers.js:
--------------------------------------------------------------------------------
1 | import lambda from '../AWS/lambda.js';
2 | import s3 from '../AWS/s3.js';
3 |
4 | import archiver from '../util/archiver.js';
5 |
6 | import { intro, starting, error, fail, finished, code } from '../util/chalkColors.js';
7 |
8 | const layers = {};
9 |
10 | layers.create = async (layerName, fileArr) => {
11 |
12 | // if(!fileArr && !layerName){
13 | // console.log(error('both fileArr and layerName are required fields'));
14 | // return;
15 | // }
16 | console.log(starting('Compressing layer files...'));
17 | const outputZip = await archiver.zipFiles(fileArr, layerName, true);
18 |
19 | console.log(starting('Sending files to S3...'));
20 | await s3.sendFile(outputZip);
21 |
22 | console.log(starting('Sending files to AWS Lambda...'));
23 | const response = await lambda.createLambdaLayer(layerName, outputZip);
24 | if (response.$metadata.httpStatusCode < 300) {
25 | console.log(finished('Request complete: Lambda layers created'));
26 | }
27 | else {
28 | console.log(error('Error with sending request to AWS Lambda'));
29 | }
30 | };
31 |
32 | layers.addLayersToFunc = async(funcName, options) => {
33 |
34 | const layerArr = [{layerName: options.layerName, layerVersion: options.layerVersion}];
35 |
36 | if(!funcName || !layerArr){
37 | console.log(error('funcName, layerName, and layerVersion are required fields'));
38 | return;
39 | }
40 | console.log(starting('Sending request to AWS Lambda...'));
41 | const response = await lambda.addLayerToFunc(funcName, layerArr);
42 | if (response.$metadata.httpStatusCode < 300) {
43 | console.log(finished('Request complete: Lambda layers added to function'));
44 | }
45 | else {
46 | console.log(error('Error with sending request to AWS Lambda'));
47 | }
48 |
49 | };
50 |
51 | export default layers;
--------------------------------------------------------------------------------
/methods/commands/roles.js:
--------------------------------------------------------------------------------
1 | import iam from '../AWS/iam.js';
2 | import { AwsRole } from '../util/aws.js';
3 | import { verifyRole } from '../util/verifyAWS.js';
4 | import { intro, starting, error, fail, finished, code } from '..//util/chalkColors.js';
5 |
6 | const roles = async (role, options) => {
7 | if (options.delete) {
8 | if (role === AwsRole) {
9 | console.log(fail('Cannot delete default role. Change default role before deleting'));
10 | return;
11 | }
12 | let data;
13 | if (options.role) data = await iam.deleteRole(options.role);
14 | if (!options.role && role !== AwsRole) data = await iam.deleteRole(role);
15 | if (data) console.log(finished(` AWS role '${options.role || role}' deleted.`));
16 | return;
17 | }
18 | if (options.list) console.log(await iam.getRoleList());
19 | if (options.role) await verifyRole(options.role, options.create);
20 | if (!options.role && role !== AwsRole) await verifyRole(role, options.create);
21 | };
22 |
23 | export default roles;
--------------------------------------------------------------------------------
/methods/util/archiver.js:
--------------------------------------------------------------------------------
1 | import path, {dirname} from 'path';
2 | import fs, { ReadStream } from 'fs';
3 | import archiver from 'archiver';
4 | import {finished as finishedStreamWriting} from 'stream/promises';
5 |
6 | import { starting, code, error, finished } from './chalkColors.js';
7 |
8 | import dotenv from 'dotenv';
9 | dotenv.config();
10 |
11 | const FOLDER = process.env.FOLDER;
12 |
13 | const archiveZip = {};
14 |
15 |
16 | //should zip files and folders
17 | archiveZip.zipFiles = async (fileArr, outputFileName = 'function', layer = false) => {
18 |
19 | // breaks up fileArr into the first file and the rest
20 | let [index, ...args] = fileArr;
21 | // if lambda layer
22 | if (layer) args = fileArr;
23 |
24 | console.log(args);
25 |
26 | console.log(starting(`Adding the following files/directories to the output zip file "${outputFileName}.zip" : `));
27 | if (!layer) console.log(code(` ${index}`));
28 |
29 | // create a file to stream archive data to.
30 | const output = fs.createWriteStream(`${outputFileName}.zip`);
31 |
32 | const archive = archiver('zip');
33 |
34 | archive.on('warning', function(err) {
35 | if (err.code === 'ENOENT') {
36 | // log warning
37 | } else {
38 | // throw error
39 | throw err;
40 | }
41 | });
42 |
43 | // if zipping a lambda function, adds the first file as index.js
44 | const stream = fs.createReadStream(path.join(`${FOLDER}`) + '/' + index);
45 | if (!layer) {
46 | const stats = fs.statSync(path.join(`${FOLDER}`) + '/' + index);
47 | if (stats.isDirectory()) archive.directory(`${FOLDER}/${index}/`, index);
48 | else archive.file(path.join(`${FOLDER}`) + '/' + index, {name: 'index.js'});
49 | }
50 |
51 | //iterate over the remaining file names in fileArr and add them as their original names
52 | for (const file of args) {
53 | console.log(code(` ${file}`));
54 | const stats = fs.statSync(path.join(`${FOLDER}`) + '/' + file);
55 | if (stats.isDirectory()) archive.directory(`${FOLDER}/${file}/`, file);
56 | else {
57 | if (layer) archive.file(path.join(`${FOLDER}`) + '/' + file, {name: `nodejs/node_modules/${file}`});
58 | else archive.file(path.join(`${FOLDER}`) + '/' + file, {name: `${file}`});
59 | }
60 | }
61 | // pipe archive data to the file
62 | archive.pipe(output);
63 |
64 | // finalize the archive (ie we are done appending files but streams have to finish yet)
65 | await archive.finalize();
66 |
67 | const data = await finishedStreamWriting(output, {}, (err) => {
68 | if(err){
69 | console.log(error('Error while zipping up file: ', err));
70 | } else{
71 | console.log('Output finished writing');
72 | }
73 | });
74 |
75 | return `${outputFileName}.zip`;
76 | };
77 |
78 |
79 | export default archiveZip;
--------------------------------------------------------------------------------
/methods/util/aws.js:
--------------------------------------------------------------------------------
1 | // set up .env file accessibility
2 | import dotenv from 'dotenv';
3 | dotenv.config();
4 |
5 | // root user credentials
6 | const credentials = {
7 | accessKeyId: process.env.AWS_ACCESS_KEY_ID,
8 | secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
9 | };
10 |
11 | // set up AWS region
12 | const AwsRegion = process.env.AWS_REGION;
13 |
14 | const AwsParams = {
15 | 'region': AwsRegion,
16 | 'credentials': credentials,
17 | };
18 |
19 | // the basic policy needed from AWS in order to create a role for lambda
20 | const BasicPolicy = {
21 | 'Version': '2012-10-17',
22 | 'Statement': [
23 | {
24 | 'Effect': 'Allow',
25 | Principal: {
26 | Service: 'lambda.amazonaws.com',
27 | },
28 | 'Action': 'sts:AssumeRole',
29 | }
30 | ]
31 | };
32 |
33 | // default ARNs
34 | const LambdaBasicARN = 'arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole';
35 |
36 | //gets the .env bucket name and awsRole
37 | const AwsBucket = process.env.S3BUCKETNAME;
38 | const AwsRole = process.env.ROLENAME;
39 | const AwsAccount = process.env.AWS_ACCOUNT;
40 |
41 |
42 |
43 | export {AwsAccount, AwsParams, AwsBucket, AwsRegion, AwsRole, BasicPolicy, LambdaBasicARN};
44 |
--------------------------------------------------------------------------------
/methods/util/chalkColors.js:
--------------------------------------------------------------------------------
1 | import chalk from 'chalk';
2 |
3 | export const intro = chalk.bold.yellow;
4 | export const code = chalk.bold;
5 | export const starting = chalk.bold;
6 | export const error = chalk.bold.red;
7 | export const fail = chalk.bold.red;
8 | export const finished = chalk.green;
9 | export const warning = chalk.bold.yellowBright;
10 |
--------------------------------------------------------------------------------
/methods/util/default.js:
--------------------------------------------------------------------------------
1 | const random = (length = 6) => {
2 | return Math.random().toString(16).slice(2, length);
3 | };
4 |
5 | const startingRegion = 'us-east-1';
6 | const startingRole = 'defaultLambdaRole';
7 | const startingBucket = 'defaultbucket-' + random();
8 | const startingFolder = '';
9 |
10 | export { startingRegion, startingRole, startingBucket, startingFolder};
--------------------------------------------------------------------------------
/methods/util/generateEnv.js:
--------------------------------------------------------------------------------
1 | import path from 'path';
2 | import fs from 'fs';
3 | import {writeFile, appendFile} from 'fs/promises';
4 |
5 | import { intro, starting, error, fail, finished, code } from './chalkColors.js';
6 | import {checkConnection} from './verifyAWS.js';
7 | import {startingBucket, startingRegion, startingRole, startingFolder} from './default.js';
8 |
9 |
10 | async function init (id, key, account, region = startingRegion, role = startingRole, bucket = startingBucket, directory = startingFolder, update) {
11 | // check if .gitignore exists
12 | if (!fs.existsSync(path.resolve('./.gitignore'))) {
13 |
14 | // if it doesn't exist, create it with .env
15 | await writeFile('./.gitignore', '.env')
16 | .catch(err => {
17 | console.log(error(`Error in creating ./.gitignore : ${err.message}`));
18 | return;
19 | });
20 | console.log('.gitignore Created');
21 | }
22 |
23 | else {
24 | // if it does exist, read gitignore
25 | fs.readFile('./.gitignore', async (err, data) => {
26 |
27 | // check for .env and add if it doesn't
28 | if (!data.includes('.env')) {
29 |
30 | //append onto gitignore
31 | await appendFile('./.gitignore', '.env')
32 | .catch(err => {
33 | console.log(error(`Error in appending to ./.gitignore : ${err.message}`));
34 | });
35 | console.log('.env Added');
36 | }
37 | });
38 | }
39 |
40 | const accountId = await checkConnection(id, key, account, region);
41 | if (!accountId) return;
42 |
43 | // remove slash if folder contains a slash as last char
44 | if (directory[directory.length - 1] === '/') directory = directory.slice(0, directory.length - 1);
45 |
46 | // create the aws credentials string
47 | const awsID = `AWS_ACCESS_KEY_ID=${id}\n`;
48 | const awsKey = `AWS_SECRET_ACCESS_KEY=${key}\n`;
49 | const awsAccount = `AWS_ACCOUNT=${accountId}\n`;
50 | const awsRegion = `AWS_REGION=${region}\n`;
51 | const s3Bucket = `S3BUCKETNAME=${bucket}\n`;
52 | const awsRole = `ROLENAME=${role}\n`;
53 | const folder = `FOLDER=${directory}\n`;
54 |
55 | // check if .env exists
56 | if (!fs.existsSync(path.resolve('./.env'))) {
57 | //if it doesn't exist, create it with .env
58 | await writeFile('./.env', awsID + awsKey + awsAccount + awsRegion + s3Bucket + awsRole + folder)
59 | .catch(err => {
60 | console.log(error(`Error writing to the file ./.env : ${err.message}`));
61 | return;
62 | });
63 | console.log('.env Created');
64 | console.log(finished('AWS configuration finished!'));
65 | }
66 | else {
67 |
68 | //if it does exist, check for check for aws credentials
69 | fs.readFile('./.env', 'utf8', async (err, data) => {
70 |
71 | // if there is an option to update
72 | if (update) {
73 | // split up the data into an array
74 | const data_array = data.split('\n');
75 | // use a helper function to determine the data to delete
76 | const textLine = (text) => {
77 | for (let i = 0; i < data_array.length; i++) {
78 | if (data_array[i] && data_array[i].match(text)) {
79 | return i;
80 | }
81 | }
82 | };
83 | // delete the three main arguments
84 | delete data_array[textLine('AWS_ACCESS_KEY_ID')];
85 | delete data_array[textLine('AWS_SECRET_ACCESS_KEY')];
86 | delete data_array[textLine('AWS_ACCOUNT')];
87 | // if there are options
88 | if (region !== startingRegion) delete data_array[textLine('AWS_REGION')];
89 | if (role && role !== startingRole) delete data_array[textLine('ROLENAME')];
90 | if (bucket && bucket !== startingBucket) delete data_array[textLine('S3BUCKETNAME')];
91 |
92 | // turn back into string while ignoring whitespaces
93 | data = '';
94 | data_array.forEach(el => {
95 | if (el !== '') data += el + '\n';
96 | });
97 | }
98 |
99 | // add all updated parameters
100 | if (!data.includes('AWS_ACCESS_KEY_ID')) {
101 | data += awsID;
102 | console.log('AWS Access Key ID Added');
103 | }
104 | if (!data.includes('AWS_SECRET_ACCESS_KEY')) {
105 | data += awsKey;
106 | console.log('AWS Secret Access Key Added');
107 | }
108 | if (!data.includes('AWS_ACCOUNT')) {
109 | data += awsAccount;
110 | console.log('AWS Account Added');
111 | }
112 | if (!data.includes('AWS_REGION')) {
113 | data += awsRegion;
114 | console.log('AWS Region Added');
115 | }
116 | if (!data.includes('ROLENAME')) {
117 | data += awsRole;
118 | console.log('Role Name Added');
119 | }
120 | if (!data.includes('S3BUCKETNAME')) {
121 | data += s3Bucket;
122 | console.log('S3 Bucket Name Added');
123 | }
124 | if (!data.includes('FOLDER')) {
125 | data += folder;
126 | console.log('Folder Name Added');
127 | }
128 |
129 | //write it back to the .env file
130 | await writeFile('./.env', data)
131 | .catch(err => {
132 | console.log(error(`Error in modifying ./.env : ${err.message}`));
133 | return;
134 | });
135 |
136 | console.log('.env finished!');
137 | console.log(finished('AWS configuration finished!'));
138 | });
139 | }
140 | }
141 |
142 | export default init;
--------------------------------------------------------------------------------
/methods/util/verifyAWS.js:
--------------------------------------------------------------------------------
1 | import { STSClient, GetAccessKeyInfoCommand } from "@aws-sdk/client-sts";
2 |
3 | import iam from '../AWS/iam.js';
4 | import s3 from '../AWS/s3.js';
5 | import lambda from "../AWS/lambda.js";
6 |
7 | import {starting, finished, warning, fail} from './chalkColors.js';
8 |
9 | // verifies that the role exists and create if create is true
10 | async function verifyRole(roleName, create = false) {
11 | const verifyResult = await iam.verifyRole(roleName);
12 | verifyResult ? console.log(finished(' Role exists\n')) : console.log(fail(' Role doesn\'t exist\n'));
13 | if (create && !verifyResult) await iam.createRole(roleName);
14 | }
15 |
16 | // verifies that the bucket exists and create if otherwise
17 | async function verifyBucket(bucket, create = false) {
18 | if (bucket !== bucket.toLowerCase()) {
19 | console.log(fail(' AWS S3 buckets must be in lower case only'));
20 | return;
21 | }
22 | const verifyResult = await s3.verifyBucket(bucket);
23 | verifyResult ? console.log(finished(' Bucket exists\n')) : console.log(fail(' Bucket doesn\'t exist\n'));
24 | if (create && !verifyResult) await s3.createBucket(bucket);
25 | }
26 |
27 | // verifies that the function is a valid function
28 | async function verifyFunction(funcName) {
29 | const functionObj = await lambda.getFuncList();
30 | const functions = Object.keys(functionObj);
31 | const result = functions.includes(funcName);
32 | result ? console.log('Verified function name') : console.log(fail('Cannot find function name.'));
33 | return result;
34 | }
35 |
36 | async function checkConnection(id, key, account, region) {
37 | const credentials = {
38 | accessKeyId: id,
39 | secretAccessKey: key
40 | };
41 |
42 | const awsParams = {
43 | 'region': region,
44 | 'credentials': credentials,
45 | };
46 |
47 | const stsClient = new STSClient(awsParams);
48 |
49 | console.log(starting('Verifying AWS credentials...'));
50 |
51 | const data = await stsClient.send(new GetAccessKeyInfoCommand({AccessKeyId: id}))
52 | .catch(error => {
53 | // error handling.
54 | console.log(fail('\nError in verifying AWS credentials'));
55 | console.log(error.message);
56 | console.log(fail('Please ensure that the ID/Key from this specific user has admin rights.'));
57 | console.log('These privileges are required to properly create and execute commands in AWS.');
58 | console.log('If you do not wish to give this specific user admin privileges, please ensure the user has S3 and Lambda read/write permissions.');
59 | return;
60 | });
61 | if (!data) {
62 | if (!account) {
63 | console.log(fail('No account number was given'));
64 | console.log('Re-run initialization or see alanajs documentation on how to properly create the .ENV file.');
65 | return false;
66 | }
67 | else {
68 | console.log(warning('The .ENV file will be created with the account number provided.'));
69 | console.log(warning('The account number could not be verified, and problems may occur if account number is incorrect'));
70 | return account;
71 | }
72 | }
73 | if (account && data.Account !== account) {
74 | console.log(fail('\nError in matching account read from AWS and the account entered. Please verify if the account number is correct.'));
75 | return;
76 | }
77 | console.log(finished(' AWS Credentials verified.'));
78 | return data.Account;
79 | }
80 |
81 | export {verifyRole, verifyBucket, verifyFunction, checkConnection};
--------------------------------------------------------------------------------
/npm_package/index.js:
--------------------------------------------------------------------------------
1 | import lambda from '../methods/AWS/lambda.js';
2 | import s3 from '../methods/AWS/s3.js';
3 | import zip from '../methods/util/archiver.js';
4 | import lambdaFunctions from '../methods/commands/functions.js';
5 | import layers from '../methods/commands/layers.js';
6 | import API from '../methods/AWS/gatewayv2';
7 |
8 | const alana = {};
9 |
10 | /**
11 | * @FunctionName: getFuncList
12 | * @Description: Displays table of lambda functions
13 | */
14 | alana.getFuncList = async () => {
15 | console.log('alana.getFuncList invoked');
16 | const functionList = await lambda.getFuncList();
17 | console.table(functionList);
18 | console.log('Finished getting Lambda function list');
19 | return functionList;
20 | };
21 |
22 | /**
23 | * @FunctionName: getFuncVersions
24 | * @Description: Displays table of function versions
25 | * @input: string that contains function name
26 | */
27 | alana.getFuncVersions = async (funcName) => {
28 | console.log('alana.getFuncVersions invoked');
29 | const versionList = await lambda.getFuncVersionList(funcName);
30 | console.table(versionList);
31 | console.log('Finished getting Lambda function versions');
32 | return versionList;
33 | };
34 |
35 | /**
36 | * @FunctionName: createFunction
37 | * @Description: creates AWS Lambda function
38 | * @input: params object which includes array of file names and name of function :options object
39 | */
40 | alana.createFunction = async (params, options = {}) => {
41 | const {fileArr, funcName} = params;
42 | console.log('alana.createFunction invoked');
43 | await lambdaFunctions.create(params.funcName, params.fileArr, options);
44 | console.log('Lambda function has been created');
45 | };
46 |
47 | /**
48 | * @FunctionName: updateFunction
49 | * @Description: updates AWS Lambda function
50 | * @input: params object which includes array of file names and name of function to be updated
51 | */
52 | alana.updateFunction = async (params) => {
53 | const {fileArr, funcName} = params;
54 | console.log('alana.updateFunction invoked');
55 | const zipFile = await zip.zipFiles(fileArr);
56 | await s3.sendFile(zipFile);
57 | await lambda.updateFunction(zipFile, funcName);
58 | console.log('Lambda function has been updated');
59 | };
60 |
61 | /**
62 | * @FunctionName: deleteFunction
63 | * @Description: deletes AWS Lambda function
64 | * @input: string which contains function name, optional qualifier
65 | */
66 | alana.deleteFunction = async (funcName, qualifier) => {
67 | console.log('alana.deleteFunction invoked');
68 | await lambda.deleteFunction(funcName, qualifier);
69 | console.log('Lambda function has been deleted');
70 | };
71 |
72 | /**
73 | * @FunctionName: createLambdaLayer
74 | * @Description: creates AWS Lambda layer
75 | * @input: params object that contains array of files and layer name
76 | */
77 | alana.createLambdaLayer = async (params) => {
78 | const {fileArr, layerName} = params;
79 | await layers.create(layerName, fileArr);
80 | };
81 |
82 | /**
83 | * @FunctionName: createAlias
84 | * @Description: creates Alias for Lambda functions
85 | * @input: params object which includes function name and version
86 | */
87 | alana.createAlias = async (params, aliasName) => {
88 | const {funcName, version} = params;
89 | console.log('alana.createAlias invoked');
90 | await lambda.createAlias(funcName, version, aliasName);
91 | console.log('Lambda Alias function has been created');
92 | };
93 |
94 | /**
95 | * @FunctionName: updateAlias
96 | * @Description: updates Alias for Lambda functions
97 | * @input: params object which includes function name and version
98 | */
99 | alana.updateAlias = async (params, aliasName) => {
100 | const {funcName, version} = params;
101 | console.log('alana.updateAlias invoked');
102 | await lambda.updateAlias(funcName, version, aliasName);
103 | console.log('Lambda Alias function has been updated');
104 | };
105 |
106 | /**
107 | * @FunctionName: deleteAlias
108 | * @Description: deletes Alias for Lambda functions
109 | * @input: params object which includes function name
110 | */
111 | alana.deleteAlias = async (params, aliasName) => {
112 | const {funcName} = params;
113 | console.log('alana.deleteAlias invoked');
114 | await lambda.deleteAlias(funcName, aliasName);
115 | console.log('Lambda Alias function has been deleted');
116 | };
117 |
118 | /**
119 | * @FunctionName: invoke
120 | * @Description: invokes Lambda function
121 | * @input: funcName - string that includes name of function : params - object
122 | * @output: result of invoked function
123 | */
124 | alana.invoke = async (funcName, params) => {
125 | console.log('alana.invoke invoked');
126 | await lambda.invoke(funcName);
127 | console.log('Lambda function has been invoked');
128 | };
129 |
130 | /**
131 | * @FunctionName: addLayerToFunc
132 | * @Description: adds Lambda layer to Lambda function
133 | * @input: funcName - string that includes name of function: layerArr - array of objects which include name of files and name of layer
134 | */
135 | alana.addLayerToFunction = async (funcName, layer) => {
136 | console.log('alana.addLayerToFunc invoked');
137 | await layers.addLayersToFunc(funcName, layer);
138 | // await lambda.addLayerToFunc(funcName, layerArr);
139 | console.log('Lambda layer added to function');
140 | };
141 |
142 | export default alana;
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "alanajs",
3 | "keywords": [
4 | "AWS",
5 | "Lambda",
6 | "AWS-Lambda",
7 | "amazon web services",
8 | "cli",
9 | "api",
10 | "api gateway",
11 | "serverless",
12 | "microservices",
13 | "AWS-SDK"
14 | ],
15 | "repository": {
16 | "type": "git",
17 | "url": "https://github.com/oslabs-beta/alanajs"
18 | },
19 | "author": "Tin Khin, Eugene Lee, Amy Liang, Jae Hyun Ha",
20 | "version": "0.9.0",
21 | "license": "MIT",
22 | "description": "A free, open source npm package that makes it easy to create and deploy Lambda functions, incorporate microservices in your application, and build on API gateway.",
23 | "homepage": "https://www.alanajs.com/",
24 | "main": "npm_package/index.js",
25 | "bin": {
26 | "alana": "./bin/cli.js"
27 | },
28 | "scripts": {
29 | "test": "jest"
30 | },
31 | "type": "module",
32 | "dependencies": {
33 | "@aws-sdk/client-apigatewayv2": "^3.48.0",
34 | "@aws-sdk/client-iam": "^3.47.0",
35 | "@aws-sdk/client-lambda": "^3.46.0",
36 | "@aws-sdk/client-s3": "^3.46.0",
37 | "@aws-sdk/client-sts": "^3.49.0",
38 | "archiver": "^5.3.0",
39 | "chalk": "^5.0.0",
40 | "commander": "^8.3.0",
41 | "dotenv": "^11.0.0",
42 | "fs": "^0.0.1-security",
43 | "path": "^0.12.7"
44 | },
45 | "devDependencies": {
46 | "aws-sdk-client-mock": "^0.5.6",
47 | "eslint": "^8.6.0",
48 | "eslint-plugin-react": "^7.28.0",
49 | "eslint-plugin-react-hooks": "^4.3.0"
50 | }
51 | }
52 |
--------------------------------------------------------------------------------