Compare commits

..

18 commits

Author SHA1 Message Date
0655240ec0
Fix typo 2022-03-13 15:40:55 +01:00
59e1445754
Change clone address from ssh to http
To use ssh you need to have an account...
2022-03-13 15:28:16 +01:00
1d2c2bd09d
Add note about the usage 2022-03-13 15:24:06 +01:00
ce450fed51
Fix error message formatting 2022-03-13 15:21:21 +01:00
bdf8c1f0f3
Remove listener for os.Kill
It's pointless to listen for that signal because the kernel will not
wait til the process finishes.
2022-03-13 15:19:49 +01:00
fe9e4c2f34
Add command output to the response 2022-03-13 15:17:57 +01:00
753b9ec7a7
Add context to command to be canceled if the connection is closed 2022-03-13 15:16:18 +01:00
3e162a3b82
Add context to the cmd log output 2022-01-23 17:14:56 +01:00
b1ac0b02f6
Update README
- Add installation instructions
- Fix example
- Add license section
2022-01-18 15:20:03 +01:00
63547ce3cb
Add stderr to the output log 2022-01-18 15:05:36 +01:00
2b1803d600
Add support to supply args to the command 2022-01-18 00:03:34 +01:00
4b316b691b
Update README
Minor tweaks...
2022-01-17 22:29:48 +01:00
736ff08c06
Update README
- Update options output
- Update call example
- Update call example output
2022-01-17 21:53:25 +01:00
7a879c746b
Fix usage indentation in the help message 2022-01-17 21:52:54 +01:00
ddaddcd6f3
Increase readablity 2022-01-17 21:46:27 +01:00
6cd5aa1953
Make dir param no longer required 2022-01-17 21:45:25 +01:00
354428dd3a
Switch to log package for all logging output 2022-01-17 19:55:42 +01:00
1ec0846abd
Add LICENSE 2022-01-17 19:37:37 +01:00
3 changed files with 86 additions and 37 deletions

21
LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 Augusto Dwenger
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -1,32 +1,57 @@
# whook
Simple Server for Webhook usage.
A simple and naive implementation of a web server for the usage with webhooks.
## Installation
**Requirements:**
- Go >= 1.17
```sh
git clone https://git.hhhammer.de/hamburghammer/whook.git
cd whook
go build
```
You should now have a `whook` executable in the directory.
## Usage
The server is build to run behind a proxy that provides `https` and some kind of
`auth` and it is not designed for long running processes.
```sh
./whook -c ./test.sh -d $(pwd)
./whook -c ./test.sh
```
The `test.sh` script contains only `echo "hellow"` so that the output after starting
the application and opening the given URL in side the browser we see following output:
The `test.sh` script contains only `echo "hellow"` so that the output after
starting the application and opening the given URL in side the browser we see
following output:
```plain
2022/01/17 19:14:28 The HTTP server is running: http://localhost:8080/
Executing a command...
hallow
2022/01/17 21:48:43 The HTTP server is running: http://localhost:8080/
2022/01/17 21:48:49 Executing a command...
2022/01/17 21:48:49 hellow
```
## Options
```plain
A small server to listen for requests to execute some particular code.
USAGE:
whook [FLAGS]
whook [FLAGS] --cmd [COMMAND [--args [ARGS]]]
FLAGS:
-c, --cmd string REQUIRED: The command to execute.
-d, --dir string REQUIRED: The Directory to execute the command.
-h, --help Prints this help message and exits.
-p, --port string Port to listen for incoming connections. (default "8080")
-a, --args strings Arguments for the command. Can be provided multiple times or as comma-separated string.
-c, --cmd string REQUIRED: The command to execute.
-d, --dir string The Directory to execute the command.
Defaults to the directory the tool was called on.
-h, --help Prints this help message and exits.
-p, --port string Port to listen for incoming connections. (default "8080")
```
## License
This project is licensed under the [MIT](LICENSE) license.

53
main.go
View file

@ -19,7 +19,8 @@ import (
var (
servePort string
isHelp bool
cmdPath string
cmd string
cmdArgs []string
commandExecDir string
)
@ -28,35 +29,41 @@ func init() {
flags.StringVarP(&servePort, "port", "p", "8080", "Port to listen for incoming connections.")
flags.BoolVarP(&isHelp, "help", "h", false, "Prints this help message and exits.")
flags.StringVarP(&cmdPath, "cmd", "c", "", "REQUIRED: The command to execute.")
flags.StringVarP(&commandExecDir, "dir", "d", "", "REQUIRED: The Directory to execute the command.")
flags.StringVarP(&cmd, "cmd", "c", "", "REQUIRED: The command to execute.")
flags.StringSliceVarP(&cmdArgs, "args", "a", []string{}, "Arguments for the command. Can be provided multiple times or as comma-separated string.")
flags.StringVarP(&commandExecDir, "dir", "d", "", "The Directory to execute the command.\nDefaults to the directory the tool was called on.")
flags.Parse()
}
// handles the webhook requests
func handler(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
defer r.Body.Close() // so I don't forget to close it -> eventhough it's not read.
fmt.Println("Executing a command...")
cmd := exec.Command(cmdPath)
cmd.Dir = commandExecDir
out, err := cmd.Output()
cmd := exec.CommandContext(r.Context(), cmd, cmdArgs...)
// set directory only if it's present.
if commandExecDir != "" {
cmd.Dir = commandExecDir
}
out, err := cmd.CombinedOutput()
if err != nil {
log.Println(err)
fmt.Fprint(w, err.Error())
w.WriteHeader(http.StatusBadGateway)
}
fmt.Println(string(out))
output := string(out)
log.Println("Command output:\n" + output)
fmt.Fprint(w, output)
w.WriteHeader(http.StatusOK)
}
func main() {
if isHelp {
printHelp()
// printing help is treated as a successful execution.
os.Exit(0)
}
err := validate()
err := validateParams()
if err != nil {
log.Fatalln(err)
}
@ -64,7 +71,7 @@ func main() {
// use the default mux because it implements the Handler interface
// which we need for the server struct.
mux := http.NewServeMux()
mux.HandleFunc("/", handler) // only add out handler on root path
mux.HandleFunc("/", handler) // only add one handler on root path
// custom server struct to set custom timeouts for better performance.
server := &http.Server{
@ -91,20 +98,19 @@ func startHTTPServer(server *http.Server, wg *sync.WaitGroup) {
log.Println("Shutting down the server...")
return
}
log.Fatalf("An unexpected error happend while running the HTTP server: %v\n", err)
log.Fatalf("An unexpected error happened while running the HTTP server: %v\n", err)
}
}
func listenToStopHTTPServer(server *http.Server, wg *sync.WaitGroup) {
defer wg.Done()
stop := make(chan os.Signal, 1)
signal.Notify(stop, os.Interrupt, os.Kill)
<-stop
signal.Notify(stop, os.Interrupt)
<-stop // block til signal is captured.
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
if err := server.Shutdown(ctx); err != nil {
log.Fatalf("An error happened on the shutdown of the server: %v", err)
}
@ -114,19 +120,16 @@ func printHelp() {
fmt.Println(`A small server to listen for requests to execute some particular code.
USAGE:
whook [FLAGS]
whook [FLAGS] --cmd [COMMAND [--args [ARGS]]
FLAGS:`)
flags.PrintDefaults()
}
// validate if required params are presend.
func validate() error {
if cmdPath == "" {
return errors.New("Missing required 'cmd' parameter")
}
if commandExecDir == "" {
return errors.New("Missing required 'dir' parameter")
// validateParams if required params are present.
func validateParams() error {
if cmd == "" {
return errors.New("missing required 'cmd' parameter")
}
return nil