cloudflared-mirror/teamnet/filter.go

166 lines
3.8 KiB
Go

package teamnet
import (
"fmt"
"net"
"net/url"
"strconv"
"time"
"github.com/google/uuid"
"github.com/pkg/errors"
"github.com/urfave/cli/v2"
)
var (
filterDeleted = cli.BoolFlag{
Name: "filter-is-deleted",
Usage: "If false (default), only show non-deleted routes. If true, only show deleted routes.",
}
filterTunnelID = cli.StringFlag{
Name: "filter-tunnel-id",
Usage: "Show only routes with the given tunnel ID.",
}
filterSubset = cli.StringFlag{
Name: "filter-network-is-subset-of",
Aliases: []string{"nsub"},
Usage: "Show only routes whose network is a subset of the given network.",
}
filterSuperset = cli.StringFlag{
Name: "filter-network-is-superset-of",
Aliases: []string{"nsup"},
Usage: "Show only routes whose network is a superset of the given network.",
}
filterComment = cli.StringFlag{
Name: "filter-comment-is",
Usage: "Show only routes with this comment.",
}
filterVnet = cli.StringFlag{
Name: "filter-virtual-network-id",
Usage: "Show only routes that are attached to the given virtual network ID.",
}
// Flags contains all filter flags.
FilterFlags = []cli.Flag{
&filterDeleted,
&filterTunnelID,
&filterSubset,
&filterSuperset,
&filterComment,
&filterVnet,
}
)
// Filter which routes get queried.
type Filter struct {
queryParams url.Values
}
// NewFromCLI parses CLI flags to discover which filters should get applied.
func NewFromCLI(c *cli.Context) (*Filter, error) {
f := &Filter{
queryParams: url.Values{},
}
// Set deletion filter
if flag := filterDeleted.Name; c.IsSet(flag) && c.Bool(flag) {
f.deleted()
} else {
f.notDeleted()
}
if subset, err := cidrFromFlag(c, filterSubset); err != nil {
return nil, err
} else if subset != nil {
f.networkIsSupersetOf(*subset)
}
if superset, err := cidrFromFlag(c, filterSuperset); err != nil {
return nil, err
} else if superset != nil {
f.networkIsSupersetOf(*superset)
}
if comment := c.String(filterComment.Name); comment != "" {
f.commentIs(comment)
}
if tunnelID := c.String(filterTunnelID.Name); tunnelID != "" {
u, err := uuid.Parse(tunnelID)
if err != nil {
return nil, errors.Wrapf(err, "Couldn't parse UUID from %s", filterTunnelID.Name)
}
f.tunnelID(u)
}
if vnetId := c.String(filterVnet.Name); vnetId != "" {
u, err := uuid.Parse(vnetId)
if err != nil {
return nil, errors.Wrapf(err, "Couldn't parse UUID from %s", filterVnet.Name)
}
f.vnetID(u)
}
if maxFetch := c.Int("max-fetch-size"); maxFetch > 0 {
f.MaxFetchSize(uint(maxFetch))
}
return f, nil
}
// Parses a CIDR from the flag. If the flag was unset, returns (nil, nil).
func cidrFromFlag(c *cli.Context, flag cli.StringFlag) (*net.IPNet, error) {
if !c.IsSet(flag.Name) {
return nil, nil
}
_, subset, err := net.ParseCIDR(c.String(flag.Name))
if err != nil {
return nil, err
} else if subset == nil {
return nil, fmt.Errorf("Invalid CIDR supplied for %s", flag.Name)
}
return subset, nil
}
func (f *Filter) commentIs(comment string) {
f.queryParams.Set("comment", comment)
}
func (f *Filter) notDeleted() {
f.queryParams.Set("is_deleted", "false")
}
func (f *Filter) deleted() {
f.queryParams.Set("is_deleted", "true")
}
func (f *Filter) networkIsSubsetOf(superset net.IPNet) {
f.queryParams.Set("network_subset", superset.String())
}
func (f *Filter) networkIsSupersetOf(subset net.IPNet) {
f.queryParams.Set("network_superset", subset.String())
}
func (f *Filter) existedAt(existedAt time.Time) {
f.queryParams.Set("existed_at", existedAt.Format(time.RFC3339))
}
func (f *Filter) tunnelID(id uuid.UUID) {
f.queryParams.Set("tunnel_id", id.String())
}
func (f *Filter) vnetID(id uuid.UUID) {
f.queryParams.Set("virtual_network_id", id.String())
}
func (f *Filter) MaxFetchSize(max uint) {
f.queryParams.Set("per_page", strconv.Itoa(int(max)))
}
func (f Filter) Encode() string {
return f.queryParams.Encode()
}