README
¶
Portal is an api-driven, in-kernel layer 2/3 load balancer.
Status
Complete/Experimental
Usage:
As a CLI
Simply run portal <COMMAND>
portal
or portal -h
will show usage and a list of commands:
portal - load balancer/proxy
Usage:
portal [flags]
portal [command]
Available Commands:
add-service Add service
remove-service Remove service
show-service Show service
show-services Show all services
set-services Set service list
set-service Set service
add-server Add server to a service
remove-server Remove server from a service
show-server Show server on a service
show-servers Show all servers on a service
set-servers Set server list on a service
add-route Add route
set-routes Set route list
show-routes Show all routes
remove-route Remove route
add-cert Add cert
set-certs Set cert list
show-certs Show all certs
remove-cert Remove cert
Flags:
-C, --api-cert="": SSL cert for the api
-H, --api-host="127.0.0.1": Listen address for the API
-k, --api-key="": SSL key for the api
-p, --api-key-password="": Password for the SSL key
-P, --api-port="8443": Listen address for the API
-t, --api-token="": Token for API Access
-r, --cluster-connection="none://": Cluster connection string (redis://127.0.0.1:6379)
-T, --cluster-token="": Cluster security token
-c, --conf="": Configuration file to load
-d, --db-connection="scribble:///var/db/portal": Database connection string
-i, --insecure[=false]: Disable tls key checking (client) and listen on http (server)
-L, --log-file="": Log file to write to
-l, --log-level="INFO": Log level to output
-s, --server[=false]: Run in server mode
Use "portal [command] --help" for more information about a command.
For usage examples, see Api and/or Cli readme
As a Server
To start portal as a server run:
portal --server
An optional config file can also be passed on startup:
portal -c /path/to/config.json
config.json
{ "api-token": "", "api-host": "127.0.0.1", "api-port": 8443, "api-key": "", "api-cert": "", "api-key-password": "", "db-connection": "scribble:///var/db/portal", "cluster-connection": "none://", "cluster-token": "", "insecure": false, "log-level": "INFO", "log-file": "", "server": true }
## API:
| Route | Description | payload | output |
| --- | --- | --- | --- |
| **Get** /services | List all services | nil | json array of service objects |
| **Post** /services | Add a service | json service object | json service object |
| **Put** /services | Reset the list of services | json array of service objects | json array of service objects |
| **Put** /services/:service_id | Reset the specified service | nil | json service object |
| **Get** /services/:service_id | Get information about a service | nil | json service object |
| **Delete** /services/:service_id | Delete a service | nil | success message or an error |
| **Get** /services/:service_id/servers | List all servers on a service | nil | json array of server objects |
| **Post** /services/:service_id/servers | Add new server to a service | json server object | json server object |
| **Put** /services/:service_id/servers | Reset the list of servers on a service | json array of server objects | json array of server objects |
| **Get** /services/:service_id/servers/:server_id | Get information about a server on a service | nil | json server object |
| **Delete** /services/:service_id/servers/:server_id | Delete a server from a service | nil | success message or an error |
| **Delete** /routes | Delete a route | subdomain, domain, and path (json or query) | success message or an error |
| **Get** /routes | List all routes | nil | json array of route objects |
| **Post** /routes | Add new route | json route object | json route object |
| **Put** /routes | Reset the list of routes | json array of route objects | json array of route objects |
| **Delete** /certs | Delete a cert | json cert object | success message or an error |
| **Get** /certs | List all certs | nil | json array of cert objects |
| **Post** /certs | Add new cert | json cert object | json cert object |
| **Put** /certs | Reset the list of certs | json array of cert objects | json array of route objects |
- **service_id** is a formatted combination of service info: type-host-port. (tcp-127_0_0_3-80)
- **server_id** is a formatted combination of server info: host-port. (192_0_0_3-8080)
For examples, see [the api's readme](api/README.md)
## Data types:
### Service:
json:
```json
{
"host": "127.0.0.1",
"port": 1234,
"type": "tcp",
"scheduler": "wlc",
"persistence": 300,
"netmask": "255.255.255.0",
"servers": []
}
json with a server:
{
"host": "127.0.0.1",
"port": 8080,
"type": "tcp",
"scheduler": "wlc",
"persistence": 300,
"netmask": "",
"servers": [
{
"host": "172.28.128.4",
"port": 8081,
"forwarder": "m",
"weight": 1,
"UpperThreshold": 0,
"LowerThreshold": 0
}
]
}
Fields:
- host: IP of the host the service is bound to.
- port: Port that the service listens to.
- type: Type of service. Either tcp or udp.
- scheduler: How to pick downstream server. On of the following: rr, wrr, lc, wlc, lblc, lblcr, dh, sh, sed, nq
- persistence: Timeout for keeping requests from the same client going to the same server
- netmask: How to group clients with persistence to servers
- servers: Array of server objects associated to the service
Server:
json:
{
"host": "127.0.0.1",
"port": 1234,
"forwarder": "m",
"weight": 1,
"upper_threshold": 0,
"lower_threshold": 0
}
Fields:
- host: IP of the host the service is bound to.
- port: Port that the service listens to.
- forwarder: Method to use to forward traffic to this server. One of the following: g (gatewaying), i (ipip), m (masquerading)
- weight: Weight to perfer this server. Set to 0 if no traffic should go to this server.
- upper_threshold: Stop sending connections to this server when this number is reached. 0 is no limit.
- lower_threshold: Restart sending connections when drains down to this number. 0 is not set.
Route:
json:
{
"subdomain": "admin",
"domain": "test.com",
"path": "/admin*",
"targets": ["http://127.0.0.1:8080/app1","http://127.0.0.2"],
"fwdpath": "/",
"page": ""
}
Fields:
- subdomain: Subdomain to match on
- domain: Domain to match on
- path: Path to match on
- targets: URIs of servers
- fwdpath: Path to forward to targets (combined with target path)
- page: Page to serve instead of routing to targets
Certificate:
json:
{
"key": "-----BEGIN PRIVATE KEY-----\nMII.../J8\n-----END PRIVATE KEY-----",
"cert": "-----BEGIN CERTIFICATE-----\nMII...aI=\n-----END CERTIFICATE-----"
}
Fields:
- key: Pem style key
- cert: Pem style certificate
Error:
json:
{
"error": "exit status 2: unexpected argument"
}
Fields:
- error: Error message
Message:
json:
{
"msg": "Success"
}
Fields:
- msg: Success message
Documentation
¶
Overview ¶
Portal is an api-driven, in-kernel layer 2/3 load balancer with http/s proxy cababilities.
Usage ¶
To run as a server, using the defaults, starting portal is as simple as
portal -s
For more specific usage information, refer to the help doc (portal -h):
Usage: portal [flags] portal [command] Available Commands: add-service Add service remove-service Remove service show-service Show service show-services Show all services set-services Set service list set-service Set service add-server Add server to a service remove-server Remove server from a service show-server Show server on a service show-servers Show all servers on a service set-servers Set server list on a service add-route Add route set-routes Set route list show-routes Show all routes remove-route Remove route add-cert Add cert set-certs Set cert list show-certs Show all certs remove-cert Remove cert Flags: -C, --api-cert="": SSL cert for the api -H, --api-host="127.0.0.1": Listen address for the API -k, --api-key="": SSL key for the api -p, --api-key-password="": Password for the SSL key -P, --api-port="8443": Listen address for the API -t, --api-token="": Token for API Access -r, --cluster-connection="none://": Cluster connection string (redis://127.0.0.1:6379) -T, --cluster-token="": Cluster security token -c, --conf="": Configuration file to load -d, --db-connection="scribble:///var/db/portal": Database connection string -i, --insecure[=false]: Disable tls key checking (client) and listen on http (server) -L, --log-file="": Log file to write to -l, --log-level="INFO": Log level to output -s, --server[=false]: Run in server mode Use "portal [command] --help" for more information about a command.
Build Specs ¶
It is build with clustering at it's core to ensure syncronization between nodes. It utilizes a multi-master replication system allowing any node to accept requests to update load balancing or proxy rules. The high-level workflow is as follows:
// every call starts by hitting the api API - setRoute - calls cluster.SetRoute // in order to ensure syncronization comes first, cluster starts the work CLUSTER - SetRoute - calls publish "set-route" // the redis clusterer utilizes the pub/sub functionality for syncronization // when it recieves a message, it calls on "common" to implement the changes SUBSCRIBER - on "set-route" - calls common.SetRoute // common contains all the logic to perform an action, as well as roll back // other "systems" upon failure, effectively "undoing" the action COMMON - SetRoute - calls proxymgr.SetRoute & database.SetRoute - rolls back proxymgr if database fails SUBSCRIBER - if common.SetRoute was successful, write success to redis for self, otherwise rollback self // the cluster member that received the request ensures all members got the update CLUSTER - returns err if not all members have set route - rolls back `common` (via publish) if not all members can set route API - if error, return 500 response, otherwise respond as fits
Portal is also extremely "pluggable", meaning that it is easy to code in another tool to be a "Balancer" or "Proxy" by matching the interfaces. Individual object (database|balancer|proxy) functions are never called directly by "common". "Common" calls package level functions such as
database.SetService
which calls/sreturns the selected "Backend's" SetService function. The type of backend (scribble/redis) is determined from the connection configuration option, as seen in the package's Init() function:
url, err := url.Parse(config.ClusterConnection) if err != nil { return fmt.Errorf("Failed to parse db connection - %v", err) } switch url.Scheme { case "redis": Clusterer = &Redis{} case "none": Clusterer = &None{} default: Clusterer = &None{} } return Clusterer.Init()
Directories
¶
Path | Synopsis |
---|---|
api handles the api routes and pertaining funtionality.
|
api handles the api routes and pertaining funtionality. |
balance handles the load balancing portion of portal.
|
balance handles the load balancing portion of portal. |
cluster handles the multi-master clustering of portal.
|
cluster handles the multi-master clustering of portal. |
commands is where all cli logic is, including starting portal as a server.
|
commands is where all cli logic is, including starting portal as a server. |
config is a central location for configuration options.
|
config is a central location for configuration options. |
core centralizes the commonly used interfaces and structs.
|
core centralizes the commonly used interfaces and structs. |
common
common contains all the logic to perform an action, as well as roll back other "systems" upon failure, effectively "undoing" the action.
|
common contains all the logic to perform an action, as well as roll back other "systems" upon failure, effectively "undoing" the action. |
database handles portal's persistant storage.
|
database handles portal's persistant storage. |
proxymgr handles the adding of 'routes' (subdomain.domain/path sets) and their 'targets' or 'page', creating a reverse proxy router.
|
proxymgr handles the adding of 'routes' (subdomain.domain/path sets) and their 'targets' or 'page', creating a reverse proxy router. |