Skip to content

Commit

Permalink
Merge pull request #17 from kenriortega/migrate-to-cobra-cli
Browse files Browse the repository at this point in the history
Migrate to cobra cli
  • Loading branch information
kenriortega authored Sep 1, 2021
2 parents 8d9d507 + 7862e10 commit b3c49a6
Show file tree
Hide file tree
Showing 14 changed files with 361 additions and 254 deletions.
87 changes: 54 additions & 33 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,64 +15,89 @@ make compile
> List of command available
```bash
-backends string
Load balanced backends, use commas to separate
-configFile string
Only config filename.yaml default ngonx.yaml (default "ngonx.yaml")
-configPath string
Config path only not filename.yaml (default "pwd")
-genkey
Action for generate hash for protected routes
-lbPort int
Port to serve to run load balancing (default 3030)
-prevkey string
Action for save a previous hash for protected routes to validate JWT
-proxyPort int
Port to serve to run proxy
-setup
Create yaml file configuration
-type string
Main Service default is proxy (default "proxy")
-version
Display version and exit
ngonxctl -h
```

```bash
This is Ngonx ctl a proxy reverse inspired on nginx & traefik

Usage:
ngonxctl [command]

Available Commands:
completion generate the autocompletion script for the specified shell
help Help about any command
lb Run ngonx as a load balancer (round robin)
proxy Run ngonx as a reverse proxy
setup Create configuration file it`s doesn`t exist
static Run ngonx as a static web server
version Print the version number of ngonxctl

Flags:
-f, --cfgfile string File setting.yml (default "ngonx.yaml")
-p, --cfgpath string Config path only (default "path/binary")
-h, --help help for ngonxctl

Use "ngonxctl [command] --help" for more information about a command.

```

> Start Proxy server first time
`genkey` command in true generate random secretkey and save on badgerdb on `badger.data`

```bash
./ngxctl -proxyPort 5000 -genkey true
./ngonxctl proxy -port 5000 -genkey true
```

`prevkey` command receive a custom secretkey and save this on badgerdb on `badger.data`

```bash
./ngxctl -proxyPort 5000 -prevkey <secretKey>
./ngonxctl proxy -port 5000 -prevkey <secretKey>
```

> Start Proxy server
```bash
./ngxctl -proxyPort 5001
./ngonxctl proxy -port 5000
```

> Start load balancer
```bash
./ngxctl -type lb --backends "http://localhost:5000,http://localhost:5001,http://localhost:5002"
./ngonxctl lb --backends "http://localhost:5000,http://localhost:5001,http://localhost:5002"
```
> Start static files server
> Start API PoC service
```bash
./ngonxctl static
```

Metrics
-----------

Currently ngonx use prometheus as a metric collector. The main service `proxy` expose for port 10000 on route `/metrics`

```bash
go run services/micro-a/api.go --port <port>
curl http://localhost:10000/metrics
```

> Start static files server

Management API & Web(coming...)
-----------

Currently ngonx use port 10001 for export a simple api to check all services

```bash
curl http://localhost:10001/api/v1/mngt/
```



> Start API PoC service
```bash
go run cmd/main.go -type static
go run services/micro-a/api.go --port <port>
```

Install badger db on window if you don`t use CGO
Expand All @@ -84,7 +109,7 @@ CGO_ENABLED=0 go get github.com/dgraph-io/badger/v3

```bash

cd ssl
cd scripts

chmod +x ./generate.sh

Expand Down Expand Up @@ -133,10 +158,6 @@ certbot renew

---

Metrics
-----------

Currently ngonx used prometheus for metric collector. The main service `proxy` expose for port 10000 on route `/metrics`

BenchMarking
------------
Expand Down
23 changes: 23 additions & 0 deletions cmd/cli/flags.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package cli

import (
"os"

"github.com/kenriortega/ngonx/pkg/config"
)

var (
// variables to store data for global usage
configFromYaml config.Config
cfgFile = "ngonx.yaml"
cfgPath, _ = os.Getwd()
errConfig error

// flags
flagPort = "port"
flagServerList = "backends"
flagGenApiKey = "genkey"
flagPrevKey = "prevkey"
flagCfgFile = "cfgfile"
flagCfgPath = "cfgpath"
)
119 changes: 69 additions & 50 deletions cmd/cli/lb.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ import (
"strings"
"time"

"github.com/kenriortega/ngonx/pkg/backoff"
"github.com/kenriortega/ngonx/pkg/logger"

domain "github.com/kenriortega/ngonx/internal/proxy/domain"

handlers "github.com/kenriortega/ngonx/internal/proxy/handlers"
"github.com/kenriortega/ngonx/pkg/backoff"
"github.com/kenriortega/ngonx/pkg/logger"
"github.com/spf13/cobra"
)

// MaxJitter will randomize over the full exponential backoff time
Expand All @@ -24,62 +24,81 @@ const MaxJitter = 1.0
// NoJitter disables the use of jitter for randomizing the exponential backoff time
const NoJitter = 0.0

func StartLB(serverList string, port int) {

if len(serverList) == 0 {
log.Fatal("Please provide one or more backends to load balance")
}

// parse servers
tokens := strings.Split(serverList, ",")
for _, tok := range tokens {
serverUrl, err := url.Parse(tok)
var lbCmd = &cobra.Command{
Use: "lb",
Short: "Run ngonx as a load balancer (round robin)",
Run: func(cmd *cobra.Command, args []string) {
port, err := cmd.Flags().GetInt(flagPort)
if err != nil {
logger.LogError(err.Error())
}
serverList, err := cmd.Flags().GetString(flagServerList)
if err != nil {
log.Fatalf(err.Error())
}
if len(serverList) == 0 {
log.Fatal("Please provide one or more backends to load balance")
}

// parse servers
tokens := strings.Split(serverList, ",")
for _, tok := range tokens {
serverUrl, err := url.Parse(tok)
if err != nil {
logger.LogError(err.Error())
}

proxy := httputil.NewSingleHostReverseProxy(serverUrl)
proxy.ErrorHandler = func(writer http.ResponseWriter, request *http.Request, e error) {
logger.LogInfo(fmt.Sprintf("[%s] %s\n", serverUrl.Host, e.Error()))
retry := handlers.GetRetryFromContext(request)

if retry < 3 {
time.Sleep(backoff.Default.Duration(retry))
ctx := context.WithValue(request.Context(), domain.RETRY, retry+1)
proxy.ServeHTTP(writer, request.WithContext(ctx))

proxy := httputil.NewSingleHostReverseProxy(serverUrl)
proxy.ErrorHandler = func(writer http.ResponseWriter, request *http.Request, e error) {
logger.LogInfo(fmt.Sprintf("[%s] %s\n", serverUrl.Host, e.Error()))
retry := handlers.GetRetryFromContext(request)
return
}

if retry < 3 {
time.Sleep(backoff.Default.Duration(retry))
ctx := context.WithValue(request.Context(), domain.RETRY, retry+1)
proxy.ServeHTTP(writer, request.WithContext(ctx))
// after 3 retries, mark this backend as down
handlers.ServerPool.MarkBackendStatus(serverUrl, false)

return
// if the same request routing for few attempts with different backends, increase the count
attempts := handlers.GetAttemptsFromContext(request)
logger.LogInfo(fmt.Sprintf("%s(%s) Attempting retry %d\n", request.RemoteAddr, request.URL.Path, attempts))
ctx := context.WithValue(request.Context(), domain.ATTEMPTS, attempts+1)
handlers.Lbalancer(writer, request.WithContext(ctx))
}

// after 3 retries, mark this backend as down
handlers.ServerPool.MarkBackendStatus(serverUrl, false)
handlers.ServerPool.AddBackend(&domain.Backend{
URL: serverUrl,
Alive: true,
ReverseProxy: proxy,
})
logger.LogInfo(fmt.Sprintf("Configured server: %s\n", serverUrl))
}

// if the same request routing for few attempts with different backends, increase the count
attempts := handlers.GetAttemptsFromContext(request)
logger.LogInfo(fmt.Sprintf("%s(%s) Attempting retry %d\n", request.RemoteAddr, request.URL.Path, attempts))
ctx := context.WithValue(request.Context(), domain.ATTEMPTS, attempts+1)
handlers.Lbalancer(writer, request.WithContext(ctx))
// create http server
server := http.Server{
Addr: fmt.Sprintf(":%d", port),
Handler: http.HandlerFunc(handlers.Lbalancer),
}

handlers.ServerPool.AddBackend(&domain.Backend{
URL: serverUrl,
Alive: true,
ReverseProxy: proxy,
})
logger.LogInfo(fmt.Sprintf("Configured server: %s\n", serverUrl))
}

// create http server
server := http.Server{
Addr: fmt.Sprintf(":%d", port),
Handler: http.HandlerFunc(handlers.Lbalancer),
}

// start health checking
go handlers.HealthCheck()

logger.LogInfo(fmt.Sprintf("Load Balancer started at :%d\n", port))
if err := server.ListenAndServe(); err != nil {
logger.LogError(err.Error())
}
// start health checking
go handlers.HealthCheck()

logger.LogInfo(fmt.Sprintf("Load Balancer started at :%d\n", port))
if err := server.ListenAndServe(); err != nil {
logger.LogError(err.Error())
}

},
}

func init() {
lbCmd.Flags().String(flagServerList, cfgFile, "Load balanced backends, use commas to separate")
lbCmd.Flags().Int(flagPort, 4000, "Port to serve to run load balancing ")

rootCmd.AddCommand(lbCmd)
}
Loading

0 comments on commit b3c49a6

Please sign in to comment.