Skip to content

Commit

Permalink
Rewrite panic to log.Panicf
Browse files Browse the repository at this point in the history
  • Loading branch information
f0o committed Jul 3, 2024
1 parent 8052904 commit 4150928
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 37 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ vite.config.ts.timestamp-*
!config.yaml.example
protobuf/*
install.yml
.gitlab-ci.yml
3 changes: 2 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"embed"
"io/fs"
"log"

"gitlab.as203038.net/AS203038/looking-glass/server"
)
Expand All @@ -14,7 +15,7 @@ var webemned embed.FS
func main() {
web, err := fs.Sub(webemned, "dist")
if err != nil {
panic(err)
log.Panicln(err)
}
server.Start(context.Background(), web)
}
4 changes: 2 additions & 2 deletions server/routers/frrouting.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: frrouting

ping:
ping:
# any:
# - ping -n -c5 {{.IP.IP}}
ipv4:
Expand All @@ -17,7 +17,7 @@ traceroute:
- traceroute -6 -w 1 -q1 -I --back --mtu -e -s {{.Cfg.Source6.IP}} {{.IP.IP}}

bgp:
route:
route:
- vtysh -c 'show bgp vrf {{.Cfg.VRF}} {{.IP.Family}} unicast {{.IP.IP}}'
community:
- vtysh -c 'show bgp vrf {{.Cfg.VRF}} ipv4 unicast community {{.Community}}'
Expand Down
5 changes: 4 additions & 1 deletion server/routers/routers.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@ var (
)

func register(name string, rt utils.Router) bool {
if name == "" {
log.Panicln("Router name cannot be empty")
}
if _, ok := _routers[name]; ok {
panic("Router already registered")
log.Panicf("Router %s already registered", name)
}
_routers[name] = rt
return true
Expand Down
123 changes: 90 additions & 33 deletions server/routers/yaml.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,84 +3,132 @@ package routers
import (
"bytes"
"embed"
"fmt"
"log"
"os"
"strings"
"text/template"

"gitlab.as203038.net/AS203038/looking-glass/server/errs"
"gitlab.as203038.net/AS203038/looking-glass/server/utils"
yaml "gopkg.in/yaml.v2"
)

// _tpl_data represents the template data used in the router YAML file.
type _tpl_data struct {
Cfg *utils.RouterConfig
IP *utils.IPNet
Community string
ASPath string
Cfg *utils.RouterConfig // Cfg holds the router configuration.
IP *utils.IPNet // IP holds the IP network information.
Community string // Community holds the community string.
ASPath string // ASPath holds the AS path information.
}

// Yaml represents the structure of a YAML file.
type Yaml struct {
Path string
Path string // Path represents the file path.
Template struct {
Name string `yaml:"name"`
Name string `yaml:"name"` // Name represents the template name.
Ping struct {
Any []string `yaml:"any"`
IPv4 []string `yaml:"ipv4"`
IPv6 []string `yaml:"ipv6"`
} `yaml:"ping"`
Any []string `yaml:"any"` // Any represents the list of ping targets for any IP address.
IPv4 []string `yaml:"ipv4"` // IPv4 represents the list of ping targets for IPv4 addresses.
IPv6 []string `yaml:"ipv6"` // IPv6 represents the list of ping targets for IPv6 addresses.
} `yaml:"ping"` // Ping represents the ping section in the template.
Traceroute struct {
Any []string `yaml:"any"`
IPv4 []string `yaml:"ipv4"`
IPv6 []string `yaml:"ipv6"`
} `yaml:"traceroute"`
Any []string `yaml:"any"` // Any represents the list of traceroute targets for any IP address.
IPv4 []string `yaml:"ipv4"` // IPv4 represents the list of traceroute targets for IPv4 addresses.
IPv6 []string `yaml:"ipv6"` // IPv6 represents the list of traceroute targets for IPv6 addresses.
} `yaml:"traceroute"` // Traceroute represents the traceroute section in the template.
BGP struct {
Route []string `yaml:"route"`
Community []string `yaml:"community"`
ASPath []string `yaml:"aspath"`
} `yaml:"bgp"`
Route []string `yaml:"route"` // Route represents the list of BGP routes.
Community []string `yaml:"community"` // Community represents the list of BGP communities.
ASPath []string `yaml:"aspath"` // ASPath represents the list of BGP AS paths.
} `yaml:"bgp"` // BGP represents the BGP section in the template.
}
}

//go:embed all:*.yml
var compiledRouters embed.FS

// init is a function that is automatically called before the program starts.
// It initializes the routers by loading them from the specified directory and bundled routers.
// It reads YAML files, unmarshals them into router templates, and registers the routers.
// If the ROUTER_DIR environment variable is set, it loads routers from the specified directory.
// If the bundled routers exist, it loads them as well.
// The function logs the registration status of each router.
func init() {
// Load all routers
// Check for ROUTER_DIR environment variable
rd := os.Getenv("ROUTER_DIR")
if rd != "" {
// Load all routers from ROUTER_DIR
files, err := os.ReadDir(rd)
if err != nil {
log.Panicf("Could not Read directory %s: %+v", rd, err)
}
log.Printf("Loading routers from %s\n", rd)
for _, file := range files {
if file.IsDir() || (!strings.HasSuffix(file.Name(), ".yml") && !strings.HasSuffix(file.Name(), ".yaml")) {
continue
}
// Rest of the code for processing the file
y := &Yaml{Path: file.Name()}
yamlFile, err := os.ReadFile(rd + "/" + y.Path)
if err != nil {
log.Panicf("Could not Read file %s/%s: %+v", rd, y.Path, err)
}
err = yaml.Unmarshal(yamlFile, &y.Template)
if err != nil {
log.Panicf("Could not Unmarshal file %s/%s: %+v", rd, y.Path, err)
}
if y.Template.Name == "" {
log.Printf("Router name cannot be empty (%s/%s)", rd, y.Path)
continue
}
register(y.Template.Name, y)
log.Printf("Router %s (%s/%s) registered\n", y.Template.Name, rd, y.Path)
}
}

// Load all bundled routers
files, err := compiledRouters.ReadDir(".")
if err != nil {
panic(err)
log.Panicf("Could not Read builtin directory: %+v", err)
}
for _, file := range files {
y := &Yaml{}
y.Path = file.Name()
y := &Yaml{Path: file.Name()}
yamlFile, err := compiledRouters.ReadFile(y.Path)
if err != nil {
panic(err)
log.Panicf("Could not Read file builtin:%s: %+v", y.Path, err)
}
err = yaml.Unmarshal(yamlFile, &y.Template)
if err != nil {
panic(err)
log.Panicf("Could not Unmarshal file builtin:%s: %+v", y.Path, err)
}
if _, ok := _routers[y.Template.Name]; !ok {
register(y.Template.Name, y)
log.Printf("Router %s (builtin:%s) registered\n", y.Template.Name, y.Path)
} else {
log.Printf("Router %s already registered\n", y.Template.Name)
}
register(y.Template.Name, y)
fmt.Printf("Router %s registered\n", y.Template.Name)
}
}

// _tpl is a helper function used to generate a list of strings based on the provided template name and data.
// It takes a template name and data as input and returns a list of strings generated from the template.
// The function first determines the appropriate template to use based on the template name and the IP version in the data.
// It then iterates over the selected template(s), executes them with the provided data, and appends the generated strings to the result list.
// If no template is found for the given name, the function returns nil and an error of type `errs.OperationUnknown`.
func (rt *Yaml) _tpl(name string, data _tpl_data) ([]string, error) {
var tpl []string
var ret []string
switch name {
case "ping":
if rt.Template.Ping.Any != nil {
tpl = rt.Template.Ping.Any
} else if data.IP.IsIPv4() {
tpl = rt.Template.Ping.Any
if data.IP.IsIPv4() {
tpl = rt.Template.Ping.IPv4
} else if data.IP.IsIPv6() {
tpl = rt.Template.Ping.IPv6
}
case "traceroute":
if rt.Template.Traceroute.Any != nil {
tpl = rt.Template.Traceroute.Any
} else if data.IP.IsIPv4() {
tpl = rt.Template.Traceroute.Any
if data.IP.IsIPv4() {
tpl = rt.Template.Traceroute.IPv4
} else if data.IP.IsIPv6() {
tpl = rt.Template.Traceroute.IPv6
Expand Down Expand Up @@ -110,22 +158,31 @@ func (rt *Yaml) _tpl(name string, data _tpl_data) ([]string, error) {
return ret, nil
}

// Ping sends a ping request to the specified IP address using the provided router configuration.
// It returns a slice of strings representing the ping response and an error if any.
func (rt *Yaml) Ping(cfg *utils.RouterConfig, ip *utils.IPNet) ([]string, error) {
return rt._tpl("ping", _tpl_data{Cfg: cfg, IP: ip})
}

// Traceroute performs a traceroute operation using the provided router configuration and IP address.
// It returns a slice of strings representing the traceroute results and an error if any.
func (rt *Yaml) Traceroute(cfg *utils.RouterConfig, ip *utils.IPNet) ([]string, error) {
return rt._tpl("traceroute", _tpl_data{Cfg: cfg, IP: ip})
}

// BGPRoute generates BGP route configuration based on the provided RouterConfig and IPNet.
// It returns a slice of strings representing the generated configuration and an error if any.
func (rt *Yaml) BGPRoute(cfg *utils.RouterConfig, ip *utils.IPNet) ([]string, error) {
return rt._tpl("bgp.route", _tpl_data{Cfg: cfg, IP: ip})
}

// BGPCommunity returns a list of strings representing the BGP community values for the given router configuration and community.
func (rt *Yaml) BGPCommunity(cfg *utils.RouterConfig, community string) ([]string, error) {
return rt._tpl("bgp.community", _tpl_data{Cfg: cfg, Community: community})
}

// BGPASPath returns a slice of strings representing the BGP AS path for the given router configuration and AS path string.
// It uses the "_tpl" method to render the "bgp.aspath" template with the provided configuration and AS path.
func (rt *Yaml) BGPASPath(cfg *utils.RouterConfig, aspath string) ([]string, error) {
return rt._tpl("bgp.aspath", _tpl_data{Cfg: cfg, ASPath: aspath})
}

0 comments on commit 4150928

Please sign in to comment.