Files
livekit/cmd/server/commands.go
Brint E. Kriebel 822f8c3944 Region Aware node selection fixes and enhancements (#141)
* cli: Allow setting the current node region with flag or env variable

Also add region to "starting LiveKit server" log.

* routing: Add region to node registration

Register the node's region on the selected router so it can be used for
region aware node selection.

Also add the region to the list-nodes output.

* regionaware: Set minDist to zero for the current node

If you don't set the minDist when leaving the loop early for a node that
matches the current region, the minDist value with still be at max. This
causes the the wrong node to be selected if the current node is the
first one the loop passes through.

Add a test that validates this change. The new test fails if this new
change is not in place.
2021-10-10 22:21:37 -07:00

194 lines
4.4 KiB
Go

package main
import (
"fmt"
"os"
"strconv"
"time"
"github.com/livekit/protocol/auth"
"github.com/livekit/protocol/utils"
"github.com/olekukonko/tablewriter"
"github.com/urfave/cli/v2"
"gopkg.in/yaml.v3"
"github.com/livekit/livekit-server/pkg/routing"
"github.com/livekit/livekit-server/pkg/service"
)
func generateKeys(c *cli.Context) error {
apiKey := utils.NewGuid(utils.APIKeyPrefix)
secret := utils.RandomSecret()
fmt.Println("API Key: ", apiKey)
fmt.Println("API Secret: ", secret)
return nil
}
func printPorts(c *cli.Context) error {
conf, err := getConfig(c)
if err != nil {
return err
}
udpPorts := make([]string, 0)
tcpPorts := make([]string, 0)
tcpPorts = append(tcpPorts, fmt.Sprintf("%d - HTTP service", conf.Port))
if conf.RTC.TCPPort != 0 {
tcpPorts = append(tcpPorts, fmt.Sprintf("%d - ICE/TCP", conf.RTC.TCPPort))
}
if conf.RTC.UDPPort != 0 {
udpPorts = append(udpPorts, fmt.Sprintf("%d - ICE/UDP", conf.RTC.UDPPort))
} else {
udpPorts = append(udpPorts, fmt.Sprintf("%d-%d - ICE/UDP range", conf.RTC.ICEPortRangeStart, conf.RTC.ICEPortRangeEnd))
}
if conf.TURN.Enabled {
if conf.TURN.TLSPort > 0 {
tcpPorts = append(tcpPorts, fmt.Sprintf("%d - TURN/TLS", conf.TURN.TLSPort))
}
if conf.TURN.UDPPort > 0 {
udpPorts = append(udpPorts, fmt.Sprintf("%d - TURN/UDP", conf.TURN.UDPPort))
}
}
fmt.Println("TCP Ports")
for _, p := range tcpPorts {
fmt.Println(p)
}
fmt.Println("UDP Ports")
for _, p := range udpPorts {
fmt.Println(p)
}
return nil
}
func createToken(c *cli.Context) error {
room := c.String("room")
identity := c.String("identity")
conf, err := getConfig(c)
if err != nil {
return err
}
// use the first API key from config
if len(conf.Keys) == 0 {
// try to load from file
if _, err := os.Stat(conf.KeyFile); err != nil {
return err
}
f, err := os.Open(conf.KeyFile)
if err != nil {
return err
}
defer func() {
_ = f.Close()
}()
decoder := yaml.NewDecoder(f)
if err = decoder.Decode(conf.Keys); err != nil {
return err
}
if len(conf.Keys) == 0 {
return fmt.Errorf("keys are not configured")
}
}
var apiKey string
var apiSecret string
for k, v := range conf.Keys {
apiKey = k
apiSecret = v
break
}
grant := &auth.VideoGrant{
RoomJoin: true,
Room: room,
}
if c.Bool("recorder") {
grant.Hidden = true
grant.SetCanPublish(false)
grant.SetCanPublishData(false)
}
at := auth.NewAccessToken(apiKey, apiSecret).
AddGrant(grant).
SetIdentity(identity).
SetValidFor(30 * 24 * time.Hour)
token, err := at.ToJWT()
if err != nil {
return err
}
fmt.Println("Token:", token)
return nil
}
func listNodes(c *cli.Context) error {
conf, err := getConfig(c)
if err != nil {
return err
}
currentNode, err := routing.NewLocalNode(conf)
if err != nil {
return err
}
router, err := service.InitializeRouter(conf, currentNode)
if err != nil {
return err
}
nodes, err := router.ListNodes()
if err != nil {
return err
}
table := tablewriter.NewWriter(os.Stdout)
table.SetHeader([]string{
"ID", "IP Address", "Region",
"CPUs", "Load",
"Clients", "Rooms", "Tracks In/Out",
"Bytes In/Out", "Packets In/Out", "Nack", "Bps In/Out", "Pps In/Out", "Nack/Sec",
"Started At", "Updated At",
})
for _, node := range nodes {
// System stats
cpus := strconv.Itoa(int(node.Stats.NumCpus))
loadAvg := fmt.Sprintf("%.2f, %.2f, %.2f", node.Stats.LoadAvgLast1Min, node.Stats.LoadAvgLast5Min, node.Stats.LoadAvgLast15Min)
// Room stats
clients := strconv.Itoa(int(node.Stats.NumClients))
rooms := strconv.Itoa(int(node.Stats.NumRooms))
tracks := fmt.Sprintf("%d / %d", node.Stats.NumTracksIn, node.Stats.NumTracksOut)
// Packet stats
bytes := fmt.Sprintf("%d / %d", node.Stats.BytesIn, node.Stats.BytesOut)
packets := fmt.Sprintf("%d / %d", node.Stats.PacketsIn, node.Stats.PacketsOut)
nack := strconv.Itoa(int(node.Stats.NackTotal))
bps := fmt.Sprintf("%.2f / %.2f", node.Stats.BytesInPerSec, node.Stats.BytesOutPerSec)
packetsPerSec := fmt.Sprintf("%.2f / %.2f", node.Stats.PacketsInPerSec, node.Stats.PacketsOutPerSec)
nackPerSec := fmt.Sprintf("%f", node.Stats.NackPerSec)
startedAt := time.Unix(node.Stats.StartedAt, 0).String()
updatedAt := time.Unix(node.Stats.UpdatedAt, 0).String()
table.Append([]string{
node.Id, node.Ip, node.Region,
cpus, loadAvg,
clients, rooms, tracks,
bytes, packets, nack, bps, packetsPerSec, nackPerSec,
startedAt, updatedAt,
})
}
table.Render()
return nil
}