add network_route type
This commit is contained in:
parent
28af02440a
commit
7181075568
358
internal/resource/network_route.go
Normal file
358
internal/resource/network_route.go
Normal file
@ -0,0 +1,358 @@
|
|||||||
|
// Copyright 2024 Matthew Rich <matthewrich.conf@gmail.com>. All rights reserved.
|
||||||
|
|
||||||
|
package resource
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
_ "io"
|
||||||
|
"net/url"
|
||||||
|
"os/exec"
|
||||||
|
"regexp"
|
||||||
|
_ "strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
ResourceTypes.Register("route", func(u *url.URL) Resource {
|
||||||
|
n := NewNetworkRoute()
|
||||||
|
return n
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
ROUTE := NODE_SPEC [ INFO_SPEC ]
|
||||||
|
NODE_SPEC := [ TYPE ] PREFIX [ tos TOS ]
|
||||||
|
[ table TABLE_ID ] [ proto RTPROTO ]
|
||||||
|
[ scope SCOPE ] [ metric METRIC ]
|
||||||
|
[ ttl-propagate { enabled | disabled } ]
|
||||||
|
INFO_SPEC := { NH | nhid ID } OPTIONS FLAGS [ nexthop NH ]...
|
||||||
|
|
||||||
|
NH := [ encap ENCAPTYPE ENCAPHDR ] [ via [ FAMILY ] ADDRESS ]
|
||||||
|
[ dev STRING ] [ weight NUMBER ] NHFLAGS
|
||||||
|
FAMILY := [ inet | inet6 | mpls | bridge | link ]
|
||||||
|
OPTIONS := FLAGS [ mtu NUMBER ] [ advmss NUMBER ] [ as [ to ] ADDRESS ]
|
||||||
|
[ rtt TIME ] [ rttvar TIME ] [ reordering NUMBER ]
|
||||||
|
[ window NUMBER ] [ cwnd NUMBER ] [ initcwnd NUMBER ]
|
||||||
|
[ ssthresh NUMBER ] [ realms REALM ] [ src ADDRESS ]
|
||||||
|
[ rto_min TIME ] [ hoplimit NUMBER ] [ initrwnd NUMBER ]
|
||||||
|
[ features FEATURES ] [ quickack BOOL ] [ congctl NAME ]
|
||||||
|
[ pref PREF ] [ expires TIME ] [ fastopen_no_cookie BOOL ]
|
||||||
|
NHFLAGS := [ onlink | pervasive ]
|
||||||
|
PREF := [ low | medium | high ]
|
||||||
|
TIME := NUMBER[s|ms]
|
||||||
|
BOOL := [1|0]
|
||||||
|
FEATURES := ecn
|
||||||
|
ENCAPTYPE := [ mpls | ip | ip6 | seg6 | seg6local | rpl | ioam6 ]
|
||||||
|
ENCAPHDR := [ MPLSLABEL | SEG6HDR | SEG6LOCAL | IOAM6HDR ]
|
||||||
|
SEG6HDR := [ mode SEGMODE ] segs ADDR1,ADDRi,ADDRn [hmac HMACKEYID] [cleanup]
|
||||||
|
SEGMODE := [ encap | inline ]
|
||||||
|
SEG6LOCAL := action ACTION [ OPTIONS ] [ count ]
|
||||||
|
ACTION := { End | End.X | End.T | End.DX2 | End.DX6 | End.DX4 |
|
||||||
|
End.DT6 | End.DT4 | End.DT46 | End.B6 | End.B6.Encaps |
|
||||||
|
End.BM | End.S | End.AS | End.AM | End.BPF }
|
||||||
|
OPTIONS := OPTION [ OPTIONS ]
|
||||||
|
OPTION := { srh SEG6HDR | nh4 ADDR | nh6 ADDR | iif DEV | oif DEV |
|
||||||
|
table TABLEID | vrftable TABLEID | endpoint PROGNAME }
|
||||||
|
IOAM6HDR := trace prealloc type IOAM6_TRACE_TYPE ns IOAM6_NAMESPACE size IOAM6_TRACE_SIZE
|
||||||
|
ROUTE_GET_FLAGS := [ fibmatch ]
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
type NetworkRouteType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
NetworkRouteTypeUnicast = "unicast"
|
||||||
|
NetworkRouteTypeLocal = "local"
|
||||||
|
NetworkRouteTypeBroadcast = "broadcast"
|
||||||
|
NetworkRouteTypeMulticast = "multicast"
|
||||||
|
NetworkRouteTypeThrow = "throw"
|
||||||
|
NetworkRouteTypeUnreachable = "unreachable"
|
||||||
|
NetworkRouteTypeProhibit = "prohibit"
|
||||||
|
NetworkRouteTypeBlackhole = "blackhole"
|
||||||
|
NetworkRouteTypeNat = "nat"
|
||||||
|
)
|
||||||
|
|
||||||
|
type NetworkRouteTableId string
|
||||||
|
|
||||||
|
const (
|
||||||
|
NetworkRouteTableLocal = "local"
|
||||||
|
NetworkRouteTableMain = "main"
|
||||||
|
NetworkRouteTableDefault = "default"
|
||||||
|
NetworkRouteTableAll = "all"
|
||||||
|
)
|
||||||
|
|
||||||
|
var NetworkRouteNumber = regexp.MustCompile(`^[0-9]+$`)
|
||||||
|
|
||||||
|
type NetworkRouteScope string
|
||||||
|
|
||||||
|
const (
|
||||||
|
NetworkRouteScopeHost = "host"
|
||||||
|
NetworkRouteScopeLink = "link"
|
||||||
|
NetworkRouteScopeGlobal = "global"
|
||||||
|
)
|
||||||
|
|
||||||
|
type NetworkRouteProto string
|
||||||
|
|
||||||
|
const (
|
||||||
|
NetworkRouteProtoKernel = "kernel"
|
||||||
|
NetworkRouteProtoBoot = "boot"
|
||||||
|
NetworkRouteProtoStatic = "static"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Manage the state of network routes
|
||||||
|
type NetworkRoute struct {
|
||||||
|
Id string
|
||||||
|
To string `json:"to"`
|
||||||
|
Interface string `json:"interface"`
|
||||||
|
Gateway string `json:"gateway"`
|
||||||
|
Metric uint `json:"metric"`
|
||||||
|
Rtid NetworkRouteTableId `json:"rtid"`
|
||||||
|
RouteType NetworkRouteType `json:"routetype"`
|
||||||
|
Scope NetworkRouteScope `json:"scope"`
|
||||||
|
Proto NetworkRouteProto `json:"proto"`
|
||||||
|
State string `json:"state"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNetworkRoute() *NetworkRoute {
|
||||||
|
return &NetworkRoute{Rtid: NetworkRouteTableMain}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NetworkRoute) URI() string {
|
||||||
|
return fmt.Sprintf("route://%s", n.Id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NetworkRoute) SetURI(uri string) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NetworkRoute) Apply() error {
|
||||||
|
|
||||||
|
switch n.State {
|
||||||
|
case "absent":
|
||||||
|
case "present":
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NetworkRoute) LoadDecl(yamlNetworkRouteResourceDeclaration string) error {
|
||||||
|
return YamlLoadDecl(yamlNetworkRouteResourceDeclaration, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NetworkRoute) ResolveId(ctx context.Context) string {
|
||||||
|
uri := fmt.Sprintf("%s?gateway=%s&interface=%s&rtid=%s&metric=%d&type=%s&scope=%s",
|
||||||
|
n.To, n.Gateway, n.Interface, n.Rtid, n.Metric, n.RouteType, n.Scope)
|
||||||
|
fmt.Printf("%#v\n", uri)
|
||||||
|
n.Id = hex.EncodeToString([]byte(uri))
|
||||||
|
return n.Id
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NetworkRoute) Read(ctx context.Context) ([]byte, error) {
|
||||||
|
var cmdArgs []string = make([]string, 17)
|
||||||
|
cmdArgs[0] = "route"
|
||||||
|
cmdArgs[1] = "show"
|
||||||
|
if len(n.To) > 0 {
|
||||||
|
cmdArgs = append(cmdArgs, "to", n.To)
|
||||||
|
}
|
||||||
|
if len(n.Rtid) > 0 {
|
||||||
|
cmdArgs = append(cmdArgs, "table", string(n.Rtid))
|
||||||
|
}
|
||||||
|
if len(n.Gateway) > 0 {
|
||||||
|
cmdArgs = append(cmdArgs, "via", n.Gateway)
|
||||||
|
}
|
||||||
|
if len(n.Proto) > 0 {
|
||||||
|
cmdArgs = append(cmdArgs, "protocol", string(n.Proto))
|
||||||
|
}
|
||||||
|
if len(n.Scope) > 0 {
|
||||||
|
cmdArgs = append(cmdArgs, "scope", string(n.Scope))
|
||||||
|
}
|
||||||
|
if len(n.RouteType) > 0 {
|
||||||
|
cmdArgs = append(cmdArgs, "type", string(n.RouteType))
|
||||||
|
}
|
||||||
|
if len(n.Interface) > 0 {
|
||||||
|
cmdArgs = append(cmdArgs, "dev", n.Interface)
|
||||||
|
}
|
||||||
|
|
||||||
|
readRouteTable, errRouteList := exec.Command("ip", cmdArgs...).Output()
|
||||||
|
if errRouteList != nil {
|
||||||
|
return nil, errRouteList
|
||||||
|
}
|
||||||
|
routes := strings.Split(string(readRouteTable), "\n")
|
||||||
|
if len(routes) == 1 {
|
||||||
|
fields := strings.Split(routes[0], " ")
|
||||||
|
numberOfFields := len(fields)
|
||||||
|
if numberOfFields > 1 {
|
||||||
|
n.To = fields[0]
|
||||||
|
for i := 1; i < numberOfFields; i += 2 {
|
||||||
|
n.SetField(fields[i], fields[i+1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
n.ResolveId(ctx)
|
||||||
|
return yaml.Marshal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NetworkRoute) SetField(name string, value string) {
|
||||||
|
switch name {
|
||||||
|
case "to":
|
||||||
|
n.To = value
|
||||||
|
case "table":
|
||||||
|
n.Rtid = NetworkRouteTableId(value)
|
||||||
|
case "via":
|
||||||
|
n.Gateway = value
|
||||||
|
case "protocol":
|
||||||
|
n.Proto = NetworkRouteProto(value)
|
||||||
|
case "scope":
|
||||||
|
n.Scope = NetworkRouteScope(value)
|
||||||
|
case "type":
|
||||||
|
n.RouteType = NetworkRouteType(value)
|
||||||
|
case "dev":
|
||||||
|
n.Interface = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NetworkRoute) GetField(name string) string {
|
||||||
|
switch name {
|
||||||
|
case "to":
|
||||||
|
return n.To
|
||||||
|
case "table":
|
||||||
|
return string(n.Rtid)
|
||||||
|
case "via":
|
||||||
|
return n.Gateway
|
||||||
|
case "protocol":
|
||||||
|
return string(n.Proto)
|
||||||
|
case "scope":
|
||||||
|
return string(n.Scope)
|
||||||
|
case "type":
|
||||||
|
return string(n.RouteType)
|
||||||
|
case "dev":
|
||||||
|
return n.Interface
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NetworkRoute) Type() string { return "route" }
|
||||||
|
|
||||||
|
func (n *NetworkRouteType) UnmarshalValue(value string) error {
|
||||||
|
switch value {
|
||||||
|
case string(NetworkRouteTypeUnicast), string(NetworkRouteTypeLocal), string(NetworkRouteTypeBroadcast), string(NetworkRouteTypeMulticast), string(NetworkRouteTypeThrow), string(NetworkRouteTypeUnreachable), string(NetworkRouteTypeProhibit), string(NetworkRouteTypeBlackhole), string(NetworkRouteTypeNat):
|
||||||
|
*n = NetworkRouteType(value)
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
return errors.New("invalid NetworkRouteType value")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NetworkRouteType) UnmarshalJSON(data []byte) error {
|
||||||
|
var s string
|
||||||
|
if unmarshalRouteTypeErr := json.Unmarshal(data, &s); unmarshalRouteTypeErr != nil {
|
||||||
|
return unmarshalRouteTypeErr
|
||||||
|
}
|
||||||
|
return n.UnmarshalValue(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NetworkRouteType) UnmarshalYAML(value *yaml.Node) error {
|
||||||
|
var s string
|
||||||
|
if err := value.Decode(&s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return n.UnmarshalValue(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NetworkRouteTableId) UnmarshalValue(value string) error {
|
||||||
|
switch value {
|
||||||
|
case NetworkRouteNumber.FindString(value):
|
||||||
|
fallthrough
|
||||||
|
case string(NetworkRouteTableLocal), string(NetworkRouteTableMain), string(NetworkRouteTableDefault), string(NetworkRouteTableAll):
|
||||||
|
*n = NetworkRouteTableId(value)
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
return errors.New("invalid NetworkRouteTableId value")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NetworkRouteTableId) UnmarshalJSON(data []byte) error {
|
||||||
|
var s string
|
||||||
|
if unmarshalRouteTypeErr := json.Unmarshal(data, &s); unmarshalRouteTypeErr != nil {
|
||||||
|
return unmarshalRouteTypeErr
|
||||||
|
}
|
||||||
|
return n.UnmarshalValue(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NetworkRouteTableId) UnmarshalYAML(value *yaml.Node) error {
|
||||||
|
var s string
|
||||||
|
if err := value.Decode(&s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return n.UnmarshalValue(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NetworkRouteScope) UnmarshalValue(value string) error {
|
||||||
|
switch value {
|
||||||
|
case NetworkRouteNumber.FindString(value):
|
||||||
|
fallthrough
|
||||||
|
case string(NetworkRouteScopeHost), string(NetworkRouteScopeLink), string(NetworkRouteScopeGlobal):
|
||||||
|
*n = NetworkRouteScope(value)
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
return errors.New("invalid NetworkRouteScope value")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NetworkRouteScope) UnmarshalJSON(data []byte) error {
|
||||||
|
var s string
|
||||||
|
if unmarshalRouteTypeErr := json.Unmarshal(data, &s); unmarshalRouteTypeErr != nil {
|
||||||
|
return unmarshalRouteTypeErr
|
||||||
|
}
|
||||||
|
return n.UnmarshalValue(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NetworkRouteScope) UnmarshalYAML(value *yaml.Node) error {
|
||||||
|
var s string
|
||||||
|
if err := value.Decode(&s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return n.UnmarshalValue(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NetworkRouteProto) UnmarshalValue(value string) error {
|
||||||
|
switch value {
|
||||||
|
case NetworkRouteNumber.FindString(value):
|
||||||
|
fallthrough
|
||||||
|
case string(NetworkRouteProtoKernel), string(NetworkRouteProtoBoot), string(NetworkRouteProtoStatic):
|
||||||
|
*n = NetworkRouteProto(value)
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
return errors.New("invalid NetworkRouteProto value")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NetworkRouteProto) UnmarshalJSON(data []byte) error {
|
||||||
|
var s string
|
||||||
|
if unmarshalRouteTypeErr := json.Unmarshal(data, &s); unmarshalRouteTypeErr != nil {
|
||||||
|
return unmarshalRouteTypeErr
|
||||||
|
}
|
||||||
|
return n.UnmarshalValue(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NetworkRouteProto) UnmarshalYAML(value *yaml.Node) error {
|
||||||
|
var s string
|
||||||
|
if err := value.Decode(&s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return n.UnmarshalValue(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NetworkRoute) UnmarshalJSON(data []byte) error {
|
||||||
|
fmt.Printf("UnmarshalJSON %#v\n", string(data))
|
||||||
|
panic(data)
|
||||||
|
if err := json.Unmarshal(data, n); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
59
internal/resource/network_route_test.go
Normal file
59
internal/resource/network_route_test.go
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
// Copyright 2024 Matthew Rich <matthewrich.conf@gmail.com>. All rights reserved.
|
||||||
|
|
||||||
|
package resource
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
_ "encoding/json"
|
||||||
|
_ "fmt"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
_ "gopkg.in/yaml.v3"
|
||||||
|
_ "io"
|
||||||
|
_ "log"
|
||||||
|
_ "net/http"
|
||||||
|
_ "net/http/httptest"
|
||||||
|
_ "net/url"
|
||||||
|
_ "os"
|
||||||
|
_ "path/filepath"
|
||||||
|
_ "strings"
|
||||||
|
_ "syscall"
|
||||||
|
"testing"
|
||||||
|
_ "time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNewNetworkRouteResource(t *testing.T) {
|
||||||
|
n := NewNetworkRoute()
|
||||||
|
assert.NotEqual(t, nil, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNetworkRouteApplyResourceTransformation(t *testing.T) {
|
||||||
|
n := NewNetworkRoute()
|
||||||
|
assert.NotEqual(t, nil, n)
|
||||||
|
|
||||||
|
//e := f.Apply()
|
||||||
|
//assert.Equal(t, nil, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadNetworkRoute(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
declarationAttributes := `
|
||||||
|
to: "192.168.0.0/24"
|
||||||
|
interface: "eth0"
|
||||||
|
gateway: "192.168.0.1"
|
||||||
|
metric: 0
|
||||||
|
routetype: "unicast"
|
||||||
|
scope: "link"
|
||||||
|
state: present
|
||||||
|
`
|
||||||
|
|
||||||
|
testRoute := NewNetworkRoute()
|
||||||
|
e := testRoute.LoadDecl(declarationAttributes)
|
||||||
|
assert.Equal(t, nil, e)
|
||||||
|
testRoute.Apply()
|
||||||
|
r, e := testRoute.Read(ctx)
|
||||||
|
|
||||||
|
assert.Nil(t, e)
|
||||||
|
assert.NotNil(t, r)
|
||||||
|
assert.Equal(t, NetworkRouteType("unicast"), testRoute.RouteType)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user