mirror of
https://github.com/akvorado/akvorado.git
synced 2025-12-12 06:24:10 +01:00
cmd: accept an !include tag for YAML files
This commit is contained in:
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -201,7 +201,7 @@ jobs:
|
|||||||
tar zcvf docker-compose-quickstart.tar.gz \
|
tar zcvf docker-compose-quickstart.tar.gz \
|
||||||
docker-compose.yml docker-compose-demo.yml .env \
|
docker-compose.yml docker-compose-demo.yml .env \
|
||||||
orchestrator/clickhouse/data/docker-entrypoint.sh \
|
orchestrator/clickhouse/data/docker-entrypoint.sh \
|
||||||
akvorado.yaml
|
akvorado*.yaml
|
||||||
|
|
||||||
# Publish release
|
# Publish release
|
||||||
- name: Publish release
|
- name: Publish release
|
||||||
|
|||||||
16
akvorado-console.yaml
Normal file
16
akvorado-console.yaml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
---
|
||||||
|
http:
|
||||||
|
cache:
|
||||||
|
type: redis
|
||||||
|
server: redis:6379
|
||||||
|
database:
|
||||||
|
saved-filters:
|
||||||
|
# These are prepopulated filters you can select in a drop-down
|
||||||
|
# menu. Users can add more filters interactively.
|
||||||
|
- description: "From Netflix"
|
||||||
|
content: >-
|
||||||
|
InIfBoundary = external AND SrcAS = AS2906
|
||||||
|
- description: "From GAFAM"
|
||||||
|
content: >-
|
||||||
|
InIfBoundary = external AND
|
||||||
|
SrcAS IN (AS15169, AS16509, AS32934, AS6185, AS8075)
|
||||||
347
akvorado-demo.yaml
Normal file
347
akvorado-demo.yaml
Normal file
@@ -0,0 +1,347 @@
|
|||||||
|
---
|
||||||
|
.demo-exporter-flows:
|
||||||
|
- &http-src
|
||||||
|
src-port: [80, 443]
|
||||||
|
dst-port: 0
|
||||||
|
protocol: tcp
|
||||||
|
size: 1300
|
||||||
|
- &http-dst
|
||||||
|
src-port: 0
|
||||||
|
dst-port: [80, 443]
|
||||||
|
protocol: tcp
|
||||||
|
size: 1300
|
||||||
|
- &quic-src
|
||||||
|
src-port: 443
|
||||||
|
dst-port: 0
|
||||||
|
protocol: udp
|
||||||
|
size: 1200
|
||||||
|
- &ssh-src
|
||||||
|
src-port: 22
|
||||||
|
dst-port: 0
|
||||||
|
protocol: tcp
|
||||||
|
size: 200
|
||||||
|
- &ssh-dst
|
||||||
|
src-port: 0
|
||||||
|
dst-port: 22
|
||||||
|
protocol: tcp
|
||||||
|
size: 300
|
||||||
|
- &to-v4-customers
|
||||||
|
dst-net: 192.0.2.0/24
|
||||||
|
dst-as: 64501
|
||||||
|
- &to-v6-customers
|
||||||
|
dst-net: 2a01:db8:cafe:1::/64
|
||||||
|
dst-as: 64501
|
||||||
|
- &to-v4-servers
|
||||||
|
dst-net: 203.0.113.0/24
|
||||||
|
dst-as: 64501
|
||||||
|
- &to-v6-servers
|
||||||
|
dst-net: 2a01:db8:cafe:2::/64
|
||||||
|
dst-as: 64501
|
||||||
|
- &from-v4-google
|
||||||
|
src-net: 216.58.206.0/24
|
||||||
|
src-as: 15169
|
||||||
|
- &from-v6-google
|
||||||
|
src-net: 2a00:1450:4007:807::2000/124
|
||||||
|
src-as: 15169
|
||||||
|
- &from-v4-facebook
|
||||||
|
src-net: 179.60.192.0/24
|
||||||
|
src-as: 32934
|
||||||
|
- &from-v6-facebook
|
||||||
|
src-net: 2a03:2880:f130:83:face:b00c:0::/112
|
||||||
|
src-as: 32934
|
||||||
|
- &from-v4-netflix
|
||||||
|
src-net: 198.38.120.0/23
|
||||||
|
src-as: 2906
|
||||||
|
- &from-v6-netflix
|
||||||
|
src-net: 2a00:86c0:115:115::/112
|
||||||
|
src-as: 2906
|
||||||
|
- &from-v4-akamai
|
||||||
|
src-net: 23.33.27.0/24
|
||||||
|
src-as: 20940
|
||||||
|
- &from-v6-akamai
|
||||||
|
src-net: 2a02:26f0:9100:28:0:17c0::/112
|
||||||
|
src-as: 20940
|
||||||
|
- &from-v4-amazon
|
||||||
|
src-net: 52.84.175.0/24
|
||||||
|
src-as: 16509
|
||||||
|
- &from-v6-amazon
|
||||||
|
src-net: 2600:9000:218d:4a00:15:74db::/112
|
||||||
|
src-as: 16509
|
||||||
|
- &from-v4-fastly
|
||||||
|
src-net: 199.232.178.0/29
|
||||||
|
src-as: 54113
|
||||||
|
- &from-v6-fastly
|
||||||
|
src-net: 2a04:4e42:1d::/126
|
||||||
|
src-as: 54113
|
||||||
|
- &from-v4-twitch
|
||||||
|
src-net: 52.223.202.128/27
|
||||||
|
src-as: 46489
|
||||||
|
- &from-v4-renater
|
||||||
|
src-net: 138.231.0.0/16
|
||||||
|
src-as: 2269
|
||||||
|
- &from-v4-random
|
||||||
|
src-net: 92.0.0.0/8
|
||||||
|
src-as: [12322, 3215, 3303, 15557, 3320, 13335, 6185, 202818, 60068, 16276, 8075, 32590]
|
||||||
|
- &from-v6-random
|
||||||
|
src-net: 2a01:cb00::/32
|
||||||
|
src-as: [12322, 3215, 3303, 15557, 3320, 13335, 6185, 202818, 60068, 16276, 8075, 32590]
|
||||||
|
|
||||||
|
"":
|
||||||
|
- snmp:
|
||||||
|
name: th2-edge1.example.com
|
||||||
|
interfaces:
|
||||||
|
10: "Transit: Telia"
|
||||||
|
11: "IX: AMSIX"
|
||||||
|
20: "core"
|
||||||
|
21: "core"
|
||||||
|
listen: 0.0.0.0:161
|
||||||
|
bmp: &bmp
|
||||||
|
target: akvorado-inlet:10179
|
||||||
|
routes:
|
||||||
|
- prefixes: 192.0.2.0/24,2a01:db8:cafe:1::/64
|
||||||
|
aspath: 64501
|
||||||
|
communities: 65401:10,65401:12
|
||||||
|
large-communities: 65401:100:200,65401:100:201
|
||||||
|
- prefixes: 203.0.113.0/24,2a01:db8:cafe:2::/64
|
||||||
|
aspath: 65401
|
||||||
|
communities: 65401:10,65401:13
|
||||||
|
large-communities: 65401:100:200,65401:100:213
|
||||||
|
- prefixes: 216.58.206.0/24,2a00:1450:4007:807::2000/124
|
||||||
|
aspath: 174,1299,15169
|
||||||
|
communities: 174:22004,174:21100
|
||||||
|
- prefixes: 179.60.192.0/24,2a03:2880:f130:83:face:b00c:0::/112
|
||||||
|
aspath: 1299,1299,32934
|
||||||
|
communities: 1299:30000,1299:30220
|
||||||
|
- prefixes: 198.38.120.0/23,2a00:86c0:115:115::/112
|
||||||
|
aspath: 5511,1299,1299,32934
|
||||||
|
communities: 1299:30000,1299:30310
|
||||||
|
- prefixes: 23.33.27.0/24,2a02:26f0:9100:28:0:17c0::/112
|
||||||
|
aspath: 174,174,174,20940
|
||||||
|
communities: 174:22002,174:21200
|
||||||
|
- prefixes: 52.84.175.0/24,2600:9000:218d:4a00:15:74db::/112
|
||||||
|
aspath: 16509
|
||||||
|
- prefixes: 199.232.178.0/29,2a04:4e42:1d::/126
|
||||||
|
aspath: 1299,54113
|
||||||
|
communities: 1299:35000,1299:35200
|
||||||
|
- prefixes: 52.223.202.128/27
|
||||||
|
aspath: 16509,46489
|
||||||
|
- prefixes: 138.231.0.0/16
|
||||||
|
aspath: 1299,174,2269,2269
|
||||||
|
communities: 1299:30000,1299:30400
|
||||||
|
- prefixes: 0.0.0.0/0
|
||||||
|
aspath: 174
|
||||||
|
- prefixes: ::/0
|
||||||
|
aspath: 1299
|
||||||
|
flows: &flows1
|
||||||
|
samplingrate: 50000
|
||||||
|
target: akvorado-inlet:2055
|
||||||
|
flows:
|
||||||
|
# Google
|
||||||
|
- per-second: 1
|
||||||
|
in-if-index: 10
|
||||||
|
out-if-index: [20, 21]
|
||||||
|
peak-hour: 16h
|
||||||
|
multiplier: 3
|
||||||
|
reverse-direction-ratio: 0.1
|
||||||
|
<<: [*from-v4-google, *to-v4-customers, *http-src]
|
||||||
|
- per-second: 0.5
|
||||||
|
in-if-index: 10
|
||||||
|
out-if-index: [20, 21]
|
||||||
|
peak-hour: 16h
|
||||||
|
multiplier: 5
|
||||||
|
reverse-direction-ratio: 0.1
|
||||||
|
<<: [*from-v4-google, *to-v4-customers, *quic-src]
|
||||||
|
- per-second: 1.4
|
||||||
|
in-if-index: 10
|
||||||
|
out-if-index: [20, 21]
|
||||||
|
peak-hour: 21h
|
||||||
|
multiplier: 3
|
||||||
|
reverse-direction-ratio: 0.1
|
||||||
|
<<: [*from-v6-google, *to-v6-customers, *http-src]
|
||||||
|
- per-second: 0.8
|
||||||
|
in-if-index: 10
|
||||||
|
out-if-index: [20, 21]
|
||||||
|
peak-hour: 21h
|
||||||
|
multiplier: 5
|
||||||
|
reverse-direction-ratio: 0.1
|
||||||
|
<<: [*from-v6-google, *to-v6-customers, *quic-src]
|
||||||
|
# Facebook
|
||||||
|
- per-second: 1.1
|
||||||
|
in-if-index: [10, 11]
|
||||||
|
out-if-index: [20, 21]
|
||||||
|
peak-hour: 16h
|
||||||
|
multiplier: 3
|
||||||
|
reverse-direction-ratio: 0.2
|
||||||
|
<<: [*from-v4-facebook, *to-v4-customers, *http-src]
|
||||||
|
- per-second: 0.2
|
||||||
|
in-if-index: [10, 11]
|
||||||
|
out-if-index: [20, 21]
|
||||||
|
peak-hour: 16h
|
||||||
|
multiplier: 3
|
||||||
|
reverse-direction-ratio: 0.2
|
||||||
|
<<: [*from-v4-facebook, *to-v4-customers, *quic-src]
|
||||||
|
- per-second: 1.8
|
||||||
|
in-if-index: [10, 11]
|
||||||
|
out-if-index: [20, 21]
|
||||||
|
peak-hour: 18h
|
||||||
|
multiplier: 3
|
||||||
|
reverse-direction-ratio: 0.2
|
||||||
|
<<: [*from-v6-facebook, *to-v6-customers, *http-src]
|
||||||
|
- per-second: 0.2
|
||||||
|
in-if-index: [10, 11]
|
||||||
|
out-if-index: [20, 21]
|
||||||
|
peak-hour: 20h
|
||||||
|
multiplier: 3
|
||||||
|
reverse-direction-ratio: 0.2
|
||||||
|
<<: [*from-v6-facebook, *to-v6-customers, *quic-src]
|
||||||
|
# Netflix
|
||||||
|
- per-second: 0.2
|
||||||
|
in-if-index: 10
|
||||||
|
out-if-index: [20, 21]
|
||||||
|
peak-hour: 22h
|
||||||
|
multiplier: 20
|
||||||
|
reverse-direction-ratio: 0.1
|
||||||
|
<<: [*from-v4-netflix, *to-v4-customers, *http-src]
|
||||||
|
- per-second: 0.7
|
||||||
|
in-if-index: 10
|
||||||
|
out-if-index: [20, 21]
|
||||||
|
peak-hour: 22h
|
||||||
|
multiplier: 20
|
||||||
|
reverse-direction-ratio: 0.1
|
||||||
|
<<: [*from-v6-netflix, *to-v6-customers, *http-src]
|
||||||
|
# Twitch
|
||||||
|
- per-second: 0.12
|
||||||
|
in-if-index: 10
|
||||||
|
out-if-index: [20, 21]
|
||||||
|
peak-hour: 21h
|
||||||
|
multiplier: 17
|
||||||
|
reverse-direction-ratio: 0.4
|
||||||
|
<<: [*from-v4-twitch, *to-v4-customers, *http-src]
|
||||||
|
# Akamai
|
||||||
|
- per-second: 0.14
|
||||||
|
in-if-index: [10, 11]
|
||||||
|
out-if-index: [20, 21]
|
||||||
|
peak-hour: 18h
|
||||||
|
multiplier: 1.3
|
||||||
|
reverse-direction-ratio: 0.1
|
||||||
|
<<: [*from-v4-akamai, *to-v4-customers, *http-src]
|
||||||
|
- per-second: 0.8
|
||||||
|
in-if-index: [10, 11]
|
||||||
|
out-if-index: [20, 21]
|
||||||
|
peak-hour: 18h
|
||||||
|
multiplier: 1.3
|
||||||
|
reverse-direction-ratio: 0.1
|
||||||
|
<<: [*from-v6-akamai, *to-v6-customers, *http-src]
|
||||||
|
# Fastly
|
||||||
|
- per-second: 0.4
|
||||||
|
in-if-index: [10, 11]
|
||||||
|
out-if-index: [20, 21]
|
||||||
|
peak-hour: 15h
|
||||||
|
multiplier: 1.3
|
||||||
|
reverse-direction-ratio: 0.1
|
||||||
|
<<: [*from-v4-fastly, *to-v4-customers, *http-src]
|
||||||
|
- per-second: 0.7
|
||||||
|
in-if-index: [10, 11]
|
||||||
|
out-if-index: [20, 21]
|
||||||
|
peak-hour: 14h
|
||||||
|
multiplier: 1.3
|
||||||
|
reverse-direction-ratio: 0.1
|
||||||
|
<<: [*from-v6-fastly, *to-v6-customers, *http-src]
|
||||||
|
# Amazon
|
||||||
|
- per-second: 0.3
|
||||||
|
in-if-index: [10, 11]
|
||||||
|
out-if-index: [20, 21]
|
||||||
|
peak-hour: 18h
|
||||||
|
multiplier: 1.3
|
||||||
|
reverse-direction-ratio: 0.15
|
||||||
|
<<: [*from-v4-amazon, *to-v4-customers, *http-src]
|
||||||
|
- per-second: 0.1
|
||||||
|
in-if-index: 10
|
||||||
|
out-if-index: [20, 21]
|
||||||
|
peak-hour: 18h
|
||||||
|
multiplier: 1.3
|
||||||
|
reverse-direction-ratio: 0.15
|
||||||
|
<<: [*from-v6-amazon, *to-v6-customers, *http-src]
|
||||||
|
|
||||||
|
# Random SSH
|
||||||
|
- per-second: 0.1
|
||||||
|
in-if-index: 10
|
||||||
|
out-if-index: [20, 21]
|
||||||
|
peak-hour: 15h
|
||||||
|
multiplier: 1.2
|
||||||
|
reverse-direction-ratio: 0.5
|
||||||
|
<<: [*from-v4-renater, *to-v4-customers, *ssh-src]
|
||||||
|
# Servers
|
||||||
|
- per-second: 0.1
|
||||||
|
in-if-index: 10
|
||||||
|
out-if-index: [20, 21]
|
||||||
|
peak-hour: 15h
|
||||||
|
multiplier: 1.2
|
||||||
|
reverse-direction-ratio: 0.2
|
||||||
|
<<: [*from-v4-renater, *to-v4-servers, *ssh-dst]
|
||||||
|
- per-second: 0.2
|
||||||
|
in-if-index: 10
|
||||||
|
out-if-index: [20, 21]
|
||||||
|
peak-hour: 15h
|
||||||
|
multiplier: 1.2
|
||||||
|
reverse-direction-ratio: 0.15
|
||||||
|
<<: [*from-v4-random, *to-v4-servers, *http-dst]
|
||||||
|
- per-second: 0.2
|
||||||
|
in-if-index: 10
|
||||||
|
out-if-index: [20, 21]
|
||||||
|
peak-hour: 15h
|
||||||
|
multiplier: 1.2
|
||||||
|
reverse-direction-ratio: 0.1
|
||||||
|
<<: [*from-v6-random, *to-v6-servers, *http-dst]
|
||||||
|
|
||||||
|
# Noise
|
||||||
|
- &random-flow
|
||||||
|
per-second: 1
|
||||||
|
in-if-index: 10
|
||||||
|
out-if-index: [20, 21]
|
||||||
|
peak-hour: 20h
|
||||||
|
multiplier: 1
|
||||||
|
protocol: [tcp, udp]
|
||||||
|
srcport: [80, 443, 22, 25461, 8080, 4500, 993, 8801]
|
||||||
|
reverse-direction-ratio: 0.25
|
||||||
|
<<: [*from-v4-random, *to-v4-customers]
|
||||||
|
- <<: [*from-v6-random, *to-v6-customers, *random-flow]
|
||||||
|
- snmp:
|
||||||
|
name: th2-edge2.example.com
|
||||||
|
interfaces:
|
||||||
|
10: "Transit: Cogent"
|
||||||
|
11: "IX: DECIX"
|
||||||
|
20: "core"
|
||||||
|
21: "core"
|
||||||
|
listen: 0.0.0.0:161
|
||||||
|
bmp:
|
||||||
|
<<: *bmp
|
||||||
|
flows:
|
||||||
|
<<: *flows1
|
||||||
|
seed: 100
|
||||||
|
- snmp:
|
||||||
|
name: dc3-edge1.example.com
|
||||||
|
interfaces:
|
||||||
|
10: "Transit: Tata"
|
||||||
|
11: "Transit: Lumen"
|
||||||
|
20: "core"
|
||||||
|
21: "core"
|
||||||
|
listen: 0.0.0.0:161
|
||||||
|
bmp:
|
||||||
|
<<: *bmp
|
||||||
|
flows:
|
||||||
|
<<: *flows1
|
||||||
|
seed: 200
|
||||||
|
- snmp:
|
||||||
|
name: dc5-edge2.example.com
|
||||||
|
interfaces:
|
||||||
|
10: "IX: FranceIX"
|
||||||
|
11: "Transit: Cogent"
|
||||||
|
20: "core"
|
||||||
|
21: "core"
|
||||||
|
listen: 0.0.0.0:161
|
||||||
|
bmp:
|
||||||
|
<<: *bmp
|
||||||
|
flows:
|
||||||
|
<<: *flows1
|
||||||
|
seed: 300
|
||||||
44
akvorado-inlet.yaml
Normal file
44
akvorado-inlet.yaml
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
---
|
||||||
|
kafka:
|
||||||
|
compression-codec: zstd
|
||||||
|
geoip:
|
||||||
|
optional: true
|
||||||
|
# When running on Docker, these paths are inside the container.
|
||||||
|
# Check docker-compose.yml for details.
|
||||||
|
asn-database: /usr/share/GeoIP/GeoLite2-ASN.mmdb
|
||||||
|
geo-database: /usr/share/GeoIP/GeoLite2-Country.mmdb
|
||||||
|
snmp:
|
||||||
|
workers: 10
|
||||||
|
communities:
|
||||||
|
::/0: public
|
||||||
|
flow:
|
||||||
|
inputs:
|
||||||
|
- type: udp
|
||||||
|
decoder: netflow
|
||||||
|
listen: 0.0.0.0:2055
|
||||||
|
workers: 6
|
||||||
|
receive-buffer: 10485760
|
||||||
|
- type: udp
|
||||||
|
decoder: sflow
|
||||||
|
listen: 0.0.0.0:6343
|
||||||
|
workers: 6
|
||||||
|
receive-buffer: 10485760
|
||||||
|
core:
|
||||||
|
workers: 6
|
||||||
|
exporter-classifiers:
|
||||||
|
# This is an example. This should be customized depending on how
|
||||||
|
# your exporters are named.
|
||||||
|
- ClassifySiteRegex(Exporter.Name, "^([^-]+)-", "$1")
|
||||||
|
- ClassifyRegion("europe")
|
||||||
|
- ClassifyTenant("acme")
|
||||||
|
- ClassifyRole("edge")
|
||||||
|
interface-classifiers:
|
||||||
|
# This is an example. This must be customized depending on the
|
||||||
|
# descriptions of your interfaces. In the following, we assume
|
||||||
|
# external interfaces are named "Transit: Cogent" Or "IX:
|
||||||
|
# FranceIX".
|
||||||
|
- |
|
||||||
|
ClassifyConnectivityRegex(Interface.Description, "^(?i)(transit|pni|ppni|ix):? ", "$1") &&
|
||||||
|
ClassifyProviderRegex(Interface.Description, "^\\S+?\\s(\\S+)", "$1") &&
|
||||||
|
ClassifyExternal()
|
||||||
|
- ClassifyInternal()
|
||||||
415
akvorado.yaml
415
akvorado.yaml
@@ -3,6 +3,7 @@
|
|||||||
# You can get all default values with `akvorado orchestrator /dev/null
|
# You can get all default values with `akvorado orchestrator /dev/null
|
||||||
# --dump --check` or `docker-compose run akvorado-orchestrator
|
# --dump --check` or `docker-compose run akvorado-orchestrator
|
||||||
# orchestrator /dev/null --dump --check`.
|
# orchestrator /dev/null --dump --check`.
|
||||||
|
|
||||||
kafka:
|
kafka:
|
||||||
topic: flows
|
topic: flows
|
||||||
version: 3.3.1
|
version: 3.3.1
|
||||||
@@ -56,414 +57,8 @@ clickhouse:
|
|||||||
# .prefixes[] |
|
# .prefixes[] |
|
||||||
# { prefix: (.ipv4Prefix // .ipv6Prefix), tenant: "google-cloud", region: .scope }
|
# { prefix: (.ipv4Prefix // .ipv6Prefix), tenant: "google-cloud", region: .scope }
|
||||||
|
|
||||||
inlet:
|
inlet: !include "akvorado-inlet.yaml"
|
||||||
kafka:
|
console: !include "akvorado-console.yaml"
|
||||||
compression-codec: zstd
|
|
||||||
geoip:
|
|
||||||
optional: true
|
|
||||||
# When running on Docker, these paths are inside the container.
|
|
||||||
# Check docker-compose.yml for details.
|
|
||||||
asn-database: /usr/share/GeoIP/GeoLite2-ASN.mmdb
|
|
||||||
geo-database: /usr/share/GeoIP/GeoLite2-Country.mmdb
|
|
||||||
snmp:
|
|
||||||
workers: 10
|
|
||||||
communities:
|
|
||||||
::/0: public
|
|
||||||
flow:
|
|
||||||
inputs:
|
|
||||||
- type: udp
|
|
||||||
decoder: netflow
|
|
||||||
listen: 0.0.0.0:2055
|
|
||||||
workers: 6
|
|
||||||
receive-buffer: 10485760
|
|
||||||
- type: udp
|
|
||||||
decoder: sflow
|
|
||||||
listen: 0.0.0.0:6343
|
|
||||||
workers: 6
|
|
||||||
receive-buffer: 10485760
|
|
||||||
core:
|
|
||||||
workers: 6
|
|
||||||
exporter-classifiers:
|
|
||||||
# This is an example. This should be customized depending on how
|
|
||||||
# your exporters are named.
|
|
||||||
- ClassifySiteRegex(Exporter.Name, "^([^-]+)-", "$1")
|
|
||||||
- ClassifyRegion("europe")
|
|
||||||
- ClassifyTenant("acme")
|
|
||||||
- ClassifyRole("edge")
|
|
||||||
interface-classifiers:
|
|
||||||
# This is an example. This must be customized depending on the
|
|
||||||
# descriptions of your interfaces. In the following, we assume
|
|
||||||
# external interfaces are named "Transit: Cogent" Or "IX:
|
|
||||||
# FranceIX".
|
|
||||||
- |
|
|
||||||
ClassifyConnectivityRegex(Interface.Description, "^(?i)(transit|pni|ppni|ix):? ", "$1") &&
|
|
||||||
ClassifyProviderRegex(Interface.Description, "^\\S+?\\s(\\S+)", "$1") &&
|
|
||||||
ClassifyExternal()
|
|
||||||
- ClassifyInternal()
|
|
||||||
|
|
||||||
console:
|
# Remove the following line if you don't want to get demo data
|
||||||
http:
|
demo-exporter: !include "akvorado-demo.yaml"
|
||||||
cache:
|
|
||||||
type: redis
|
|
||||||
server: redis:6379
|
|
||||||
database:
|
|
||||||
saved-filters:
|
|
||||||
# These are prepopulated filters you can select in a drop-down
|
|
||||||
# menu. Users can add more filters interactively.
|
|
||||||
- description: "From Netflix"
|
|
||||||
content: >-
|
|
||||||
InIfBoundary = external AND SrcAS = AS2906
|
|
||||||
- description: "From GAFAM"
|
|
||||||
content: >-
|
|
||||||
InIfBoundary = external AND
|
|
||||||
SrcAS IN (AS15169, AS16509, AS32934, AS6185, AS8075)
|
|
||||||
|
|
||||||
# The remaining of this configuration file should be removed if you
|
|
||||||
# don't want to get demo data.
|
|
||||||
|
|
||||||
.demo-exporter-flows:
|
|
||||||
- &http-src
|
|
||||||
src-port: [80, 443]
|
|
||||||
dst-port: 0
|
|
||||||
protocol: tcp
|
|
||||||
size: 1300
|
|
||||||
- &http-dst
|
|
||||||
src-port: 0
|
|
||||||
dst-port: [80, 443]
|
|
||||||
protocol: tcp
|
|
||||||
size: 1300
|
|
||||||
- &quic-src
|
|
||||||
src-port: 443
|
|
||||||
dst-port: 0
|
|
||||||
protocol: udp
|
|
||||||
size: 1200
|
|
||||||
- &ssh-src
|
|
||||||
src-port: 22
|
|
||||||
dst-port: 0
|
|
||||||
protocol: tcp
|
|
||||||
size: 200
|
|
||||||
- &ssh-dst
|
|
||||||
src-port: 0
|
|
||||||
dst-port: 22
|
|
||||||
protocol: tcp
|
|
||||||
size: 300
|
|
||||||
- &to-v4-customers
|
|
||||||
dst-net: 192.0.2.0/24
|
|
||||||
dst-as: 64501
|
|
||||||
- &to-v6-customers
|
|
||||||
dst-net: 2a01:db8:cafe:1::/64
|
|
||||||
dst-as: 64501
|
|
||||||
- &to-v4-servers
|
|
||||||
dst-net: 203.0.113.0/24
|
|
||||||
dst-as: 64501
|
|
||||||
- &to-v6-servers
|
|
||||||
dst-net: 2a01:db8:cafe:2::/64
|
|
||||||
dst-as: 64501
|
|
||||||
- &from-v4-google
|
|
||||||
src-net: 216.58.206.0/24
|
|
||||||
src-as: 15169
|
|
||||||
- &from-v6-google
|
|
||||||
src-net: 2a00:1450:4007:807::2000/124
|
|
||||||
src-as: 15169
|
|
||||||
- &from-v4-facebook
|
|
||||||
src-net: 179.60.192.0/24
|
|
||||||
src-as: 32934
|
|
||||||
- &from-v6-facebook
|
|
||||||
src-net: 2a03:2880:f130:83:face:b00c:0::/112
|
|
||||||
src-as: 32934
|
|
||||||
- &from-v4-netflix
|
|
||||||
src-net: 198.38.120.0/23
|
|
||||||
src-as: 2906
|
|
||||||
- &from-v6-netflix
|
|
||||||
src-net: 2a00:86c0:115:115::/112
|
|
||||||
src-as: 2906
|
|
||||||
- &from-v4-akamai
|
|
||||||
src-net: 23.33.27.0/24
|
|
||||||
src-as: 20940
|
|
||||||
- &from-v6-akamai
|
|
||||||
src-net: 2a02:26f0:9100:28:0:17c0::/112
|
|
||||||
src-as: 20940
|
|
||||||
- &from-v4-amazon
|
|
||||||
src-net: 52.84.175.0/24
|
|
||||||
src-as: 16509
|
|
||||||
- &from-v6-amazon
|
|
||||||
src-net: 2600:9000:218d:4a00:15:74db::/112
|
|
||||||
src-as: 16509
|
|
||||||
- &from-v4-fastly
|
|
||||||
src-net: 199.232.178.0/29
|
|
||||||
src-as: 54113
|
|
||||||
- &from-v6-fastly
|
|
||||||
src-net: 2a04:4e42:1d::/126
|
|
||||||
src-as: 54113
|
|
||||||
- &from-v4-twitch
|
|
||||||
src-net: 52.223.202.128/27
|
|
||||||
src-as: 46489
|
|
||||||
- &from-v4-renater
|
|
||||||
src-net: 138.231.0.0/16
|
|
||||||
src-as: 2269
|
|
||||||
- &from-v4-random
|
|
||||||
src-net: 92.0.0.0/8
|
|
||||||
src-as: [12322, 3215, 3303, 15557, 3320, 13335, 6185, 202818, 60068, 16276, 8075, 32590]
|
|
||||||
- &from-v6-random
|
|
||||||
src-net: 2a01:cb00::/32
|
|
||||||
src-as: [12322, 3215, 3303, 15557, 3320, 13335, 6185, 202818, 60068, 16276, 8075, 32590]
|
|
||||||
|
|
||||||
demo-exporter:
|
|
||||||
- snmp:
|
|
||||||
name: th2-edge1.example.com
|
|
||||||
interfaces:
|
|
||||||
10: "Transit: Telia"
|
|
||||||
11: "IX: AMSIX"
|
|
||||||
20: "core"
|
|
||||||
21: "core"
|
|
||||||
listen: 0.0.0.0:161
|
|
||||||
bmp: &bmp
|
|
||||||
target: akvorado-inlet:10179
|
|
||||||
routes:
|
|
||||||
- prefixes: 192.0.2.0/24,2a01:db8:cafe:1::/64
|
|
||||||
aspath: 64501
|
|
||||||
communities: 65401:10,65401:12
|
|
||||||
large-communities: 65401:100:200,65401:100:201
|
|
||||||
- prefixes: 203.0.113.0/24,2a01:db8:cafe:2::/64
|
|
||||||
aspath: 65401
|
|
||||||
communities: 65401:10,65401:13
|
|
||||||
large-communities: 65401:100:200,65401:100:213
|
|
||||||
- prefixes: 216.58.206.0/24,2a00:1450:4007:807::2000/124
|
|
||||||
aspath: 174,1299,15169
|
|
||||||
communities: 174:22004,174:21100
|
|
||||||
- prefixes: 179.60.192.0/24,2a03:2880:f130:83:face:b00c:0::/112
|
|
||||||
aspath: 1299,1299,32934
|
|
||||||
communities: 1299:30000,1299:30220
|
|
||||||
- prefixes: 198.38.120.0/23,2a00:86c0:115:115::/112
|
|
||||||
aspath: 5511,1299,1299,32934
|
|
||||||
communities: 1299:30000,1299:30310
|
|
||||||
- prefixes: 23.33.27.0/24,2a02:26f0:9100:28:0:17c0::/112
|
|
||||||
aspath: 174,174,174,20940
|
|
||||||
communities: 174:22002,174:21200
|
|
||||||
- prefixes: 52.84.175.0/24,2600:9000:218d:4a00:15:74db::/112
|
|
||||||
aspath: 16509
|
|
||||||
- prefixes: 199.232.178.0/29,2a04:4e42:1d::/126
|
|
||||||
aspath: 1299,54113
|
|
||||||
communities: 1299:35000,1299:35200
|
|
||||||
- prefixes: 52.223.202.128/27
|
|
||||||
aspath: 16509,46489
|
|
||||||
- prefixes: 138.231.0.0/16
|
|
||||||
aspath: 1299,174,2269,2269
|
|
||||||
communities: 1299:30000,1299:30400
|
|
||||||
- prefixes: 0.0.0.0/0
|
|
||||||
aspath: 174
|
|
||||||
- prefixes: ::/0
|
|
||||||
aspath: 1299
|
|
||||||
flows: &flows1
|
|
||||||
samplingrate: 50000
|
|
||||||
target: akvorado-inlet:2055
|
|
||||||
flows:
|
|
||||||
# Google
|
|
||||||
- per-second: 1
|
|
||||||
in-if-index: 10
|
|
||||||
out-if-index: [20, 21]
|
|
||||||
peak-hour: 16h
|
|
||||||
multiplier: 3
|
|
||||||
reverse-direction-ratio: 0.1
|
|
||||||
<<: [*from-v4-google, *to-v4-customers, *http-src]
|
|
||||||
- per-second: 0.5
|
|
||||||
in-if-index: 10
|
|
||||||
out-if-index: [20, 21]
|
|
||||||
peak-hour: 16h
|
|
||||||
multiplier: 5
|
|
||||||
reverse-direction-ratio: 0.1
|
|
||||||
<<: [*from-v4-google, *to-v4-customers, *quic-src]
|
|
||||||
- per-second: 1.4
|
|
||||||
in-if-index: 10
|
|
||||||
out-if-index: [20, 21]
|
|
||||||
peak-hour: 21h
|
|
||||||
multiplier: 3
|
|
||||||
reverse-direction-ratio: 0.1
|
|
||||||
<<: [*from-v6-google, *to-v6-customers, *http-src]
|
|
||||||
- per-second: 0.8
|
|
||||||
in-if-index: 10
|
|
||||||
out-if-index: [20, 21]
|
|
||||||
peak-hour: 21h
|
|
||||||
multiplier: 5
|
|
||||||
reverse-direction-ratio: 0.1
|
|
||||||
<<: [*from-v6-google, *to-v6-customers, *quic-src]
|
|
||||||
# Facebook
|
|
||||||
- per-second: 1.1
|
|
||||||
in-if-index: [10, 11]
|
|
||||||
out-if-index: [20, 21]
|
|
||||||
peak-hour: 16h
|
|
||||||
multiplier: 3
|
|
||||||
reverse-direction-ratio: 0.2
|
|
||||||
<<: [*from-v4-facebook, *to-v4-customers, *http-src]
|
|
||||||
- per-second: 0.2
|
|
||||||
in-if-index: [10, 11]
|
|
||||||
out-if-index: [20, 21]
|
|
||||||
peak-hour: 16h
|
|
||||||
multiplier: 3
|
|
||||||
reverse-direction-ratio: 0.2
|
|
||||||
<<: [*from-v4-facebook, *to-v4-customers, *quic-src]
|
|
||||||
- per-second: 1.8
|
|
||||||
in-if-index: [10, 11]
|
|
||||||
out-if-index: [20, 21]
|
|
||||||
peak-hour: 18h
|
|
||||||
multiplier: 3
|
|
||||||
reverse-direction-ratio: 0.2
|
|
||||||
<<: [*from-v6-facebook, *to-v6-customers, *http-src]
|
|
||||||
- per-second: 0.2
|
|
||||||
in-if-index: [10, 11]
|
|
||||||
out-if-index: [20, 21]
|
|
||||||
peak-hour: 20h
|
|
||||||
multiplier: 3
|
|
||||||
reverse-direction-ratio: 0.2
|
|
||||||
<<: [*from-v6-facebook, *to-v6-customers, *quic-src]
|
|
||||||
# Netflix
|
|
||||||
- per-second: 0.2
|
|
||||||
in-if-index: 10
|
|
||||||
out-if-index: [20, 21]
|
|
||||||
peak-hour: 22h
|
|
||||||
multiplier: 20
|
|
||||||
reverse-direction-ratio: 0.1
|
|
||||||
<<: [*from-v4-netflix, *to-v4-customers, *http-src]
|
|
||||||
- per-second: 0.7
|
|
||||||
in-if-index: 10
|
|
||||||
out-if-index: [20, 21]
|
|
||||||
peak-hour: 22h
|
|
||||||
multiplier: 20
|
|
||||||
reverse-direction-ratio: 0.1
|
|
||||||
<<: [*from-v6-netflix, *to-v6-customers, *http-src]
|
|
||||||
# Twitch
|
|
||||||
- per-second: 0.12
|
|
||||||
in-if-index: 10
|
|
||||||
out-if-index: [20, 21]
|
|
||||||
peak-hour: 21h
|
|
||||||
multiplier: 17
|
|
||||||
reverse-direction-ratio: 0.4
|
|
||||||
<<: [*from-v4-twitch, *to-v4-customers, *http-src]
|
|
||||||
# Akamai
|
|
||||||
- per-second: 0.14
|
|
||||||
in-if-index: [10, 11]
|
|
||||||
out-if-index: [20, 21]
|
|
||||||
peak-hour: 18h
|
|
||||||
multiplier: 1.3
|
|
||||||
reverse-direction-ratio: 0.1
|
|
||||||
<<: [*from-v4-akamai, *to-v4-customers, *http-src]
|
|
||||||
- per-second: 0.8
|
|
||||||
in-if-index: [10, 11]
|
|
||||||
out-if-index: [20, 21]
|
|
||||||
peak-hour: 18h
|
|
||||||
multiplier: 1.3
|
|
||||||
reverse-direction-ratio: 0.1
|
|
||||||
<<: [*from-v6-akamai, *to-v6-customers, *http-src]
|
|
||||||
# Fastly
|
|
||||||
- per-second: 0.4
|
|
||||||
in-if-index: [10, 11]
|
|
||||||
out-if-index: [20, 21]
|
|
||||||
peak-hour: 15h
|
|
||||||
multiplier: 1.3
|
|
||||||
reverse-direction-ratio: 0.1
|
|
||||||
<<: [*from-v4-fastly, *to-v4-customers, *http-src]
|
|
||||||
- per-second: 0.7
|
|
||||||
in-if-index: [10, 11]
|
|
||||||
out-if-index: [20, 21]
|
|
||||||
peak-hour: 14h
|
|
||||||
multiplier: 1.3
|
|
||||||
reverse-direction-ratio: 0.1
|
|
||||||
<<: [*from-v6-fastly, *to-v6-customers, *http-src]
|
|
||||||
# Amazon
|
|
||||||
- per-second: 0.3
|
|
||||||
in-if-index: [10, 11]
|
|
||||||
out-if-index: [20, 21]
|
|
||||||
peak-hour: 18h
|
|
||||||
multiplier: 1.3
|
|
||||||
reverse-direction-ratio: 0.15
|
|
||||||
<<: [*from-v4-amazon, *to-v4-customers, *http-src]
|
|
||||||
- per-second: 0.1
|
|
||||||
in-if-index: 10
|
|
||||||
out-if-index: [20, 21]
|
|
||||||
peak-hour: 18h
|
|
||||||
multiplier: 1.3
|
|
||||||
reverse-direction-ratio: 0.15
|
|
||||||
<<: [*from-v6-amazon, *to-v6-customers, *http-src]
|
|
||||||
|
|
||||||
# Random SSH
|
|
||||||
- per-second: 0.1
|
|
||||||
in-if-index: 10
|
|
||||||
out-if-index: [20, 21]
|
|
||||||
peak-hour: 15h
|
|
||||||
multiplier: 1.2
|
|
||||||
reverse-direction-ratio: 0.5
|
|
||||||
<<: [*from-v4-renater, *to-v4-customers, *ssh-src]
|
|
||||||
# Servers
|
|
||||||
- per-second: 0.1
|
|
||||||
in-if-index: 10
|
|
||||||
out-if-index: [20, 21]
|
|
||||||
peak-hour: 15h
|
|
||||||
multiplier: 1.2
|
|
||||||
reverse-direction-ratio: 0.2
|
|
||||||
<<: [*from-v4-renater, *to-v4-servers, *ssh-dst]
|
|
||||||
- per-second: 0.2
|
|
||||||
in-if-index: 10
|
|
||||||
out-if-index: [20, 21]
|
|
||||||
peak-hour: 15h
|
|
||||||
multiplier: 1.2
|
|
||||||
reverse-direction-ratio: 0.15
|
|
||||||
<<: [*from-v4-random, *to-v4-servers, *http-dst]
|
|
||||||
- per-second: 0.2
|
|
||||||
in-if-index: 10
|
|
||||||
out-if-index: [20, 21]
|
|
||||||
peak-hour: 15h
|
|
||||||
multiplier: 1.2
|
|
||||||
reverse-direction-ratio: 0.1
|
|
||||||
<<: [*from-v6-random, *to-v6-servers, *http-dst]
|
|
||||||
|
|
||||||
# Noise
|
|
||||||
- &random-flow
|
|
||||||
per-second: 1
|
|
||||||
in-if-index: 10
|
|
||||||
out-if-index: [20, 21]
|
|
||||||
peak-hour: 20h
|
|
||||||
multiplier: 1
|
|
||||||
protocol: [tcp, udp]
|
|
||||||
srcport: [80, 443, 22, 25461, 8080, 4500, 993, 8801]
|
|
||||||
reverse-direction-ratio: 0.25
|
|
||||||
<<: [*from-v4-random, *to-v4-customers]
|
|
||||||
- <<: [*from-v6-random, *to-v6-customers, *random-flow]
|
|
||||||
- snmp:
|
|
||||||
name: th2-edge2.example.com
|
|
||||||
interfaces:
|
|
||||||
10: "Transit: Cogent"
|
|
||||||
11: "IX: DECIX"
|
|
||||||
20: "core"
|
|
||||||
21: "core"
|
|
||||||
listen: 0.0.0.0:161
|
|
||||||
bmp:
|
|
||||||
<<: *bmp
|
|
||||||
flows:
|
|
||||||
<<: *flows1
|
|
||||||
seed: 100
|
|
||||||
- snmp:
|
|
||||||
name: dc3-edge1.example.com
|
|
||||||
interfaces:
|
|
||||||
10: "Transit: Tata"
|
|
||||||
11: "Transit: Lumen"
|
|
||||||
20: "core"
|
|
||||||
21: "core"
|
|
||||||
listen: 0.0.0.0:161
|
|
||||||
bmp:
|
|
||||||
<<: *bmp
|
|
||||||
flows:
|
|
||||||
<<: *flows1
|
|
||||||
seed: 200
|
|
||||||
- snmp:
|
|
||||||
name: dc5-edge2.example.com
|
|
||||||
interfaces:
|
|
||||||
10: "IX: FranceIX"
|
|
||||||
11: "Transit: Cogent"
|
|
||||||
20: "core"
|
|
||||||
21: "core"
|
|
||||||
listen: 0.0.0.0:161
|
|
||||||
bmp:
|
|
||||||
<<: *bmp
|
|
||||||
flows:
|
|
||||||
<<: *flows1
|
|
||||||
seed: 300
|
|
||||||
|
|||||||
@@ -6,11 +6,11 @@ package cmd
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"mime"
|
"mime"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -19,7 +19,8 @@ import (
|
|||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/go-playground/validator/v10"
|
"github.com/go-playground/validator/v10"
|
||||||
"github.com/mitchellh/mapstructure"
|
"github.com/mitchellh/mapstructure"
|
||||||
"gopkg.in/yaml.v3"
|
|
||||||
|
"akvorado/common/helpers/yaml"
|
||||||
|
|
||||||
"akvorado/common/helpers"
|
"akvorado/common/helpers"
|
||||||
)
|
)
|
||||||
@@ -66,11 +67,15 @@ func (c ConfigRelatedOptions) Parse(out io.Writer, component string, config inte
|
|||||||
return fmt.Errorf("unable to parse YAML configuration file: %w", err)
|
return fmt.Errorf("unable to parse YAML configuration file: %w", err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
input, err := ioutil.ReadFile(cfgFile)
|
cfgFile, err := filepath.EvalSymlinks(cfgFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to read configuration file: %w", err)
|
return fmt.Errorf("cannot follow symlink: %w", err)
|
||||||
}
|
}
|
||||||
if err := yaml.Unmarshal(input, &rawConfig); err != nil {
|
dirname, filename := filepath.Split(cfgFile)
|
||||||
|
if dirname == "" {
|
||||||
|
dirname = "."
|
||||||
|
}
|
||||||
|
if err := yaml.UnmarshalWithInclude(os.DirFS(dirname), filename, &rawConfig); err != nil {
|
||||||
return fmt.Errorf("unable to parse YAML configuration file: %w", err)
|
return fmt.Errorf("unable to parse YAML configuration file: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,8 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"gopkg.in/yaml.v3"
|
|
||||||
|
"akvorado/common/helpers/yaml"
|
||||||
|
|
||||||
"akvorado/cmd"
|
"akvorado/cmd"
|
||||||
"akvorado/common/helpers"
|
"akvorado/common/helpers"
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import (
|
|||||||
"akvorado/common/helpers"
|
"akvorado/common/helpers"
|
||||||
"akvorado/common/reporter"
|
"akvorado/common/reporter"
|
||||||
|
|
||||||
"gopkg.in/yaml.v3"
|
"akvorado/common/helpers/yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestOrchestratorStart(t *testing.T) {
|
func TestOrchestratorStart(t *testing.T) {
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ import (
|
|||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/mitchellh/mapstructure"
|
"github.com/mitchellh/mapstructure"
|
||||||
"gopkg.in/yaml.v3"
|
|
||||||
|
"akvorado/common/helpers/yaml"
|
||||||
|
|
||||||
"akvorado/common/helpers"
|
"akvorado/common/helpers"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/mitchellh/mapstructure"
|
"github.com/mitchellh/mapstructure"
|
||||||
"gopkg.in/yaml.v3"
|
|
||||||
|
"akvorado/common/helpers/yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ConfigurationDecodeCases describes a test case for configuration
|
// ConfigurationDecodeCases describes a test case for configuration
|
||||||
|
|||||||
13
common/helpers/yaml/marshal.go
Normal file
13
common/helpers/yaml/marshal.go
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2023 Free Mobile
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
package yaml
|
||||||
|
|
||||||
|
import "gopkg.in/yaml.v3"
|
||||||
|
|
||||||
|
// Marshal serializes the value provided into a YAML document. The structure of
|
||||||
|
// the generated document will reflect the structure of the value itself. Maps
|
||||||
|
// and pointers (to struct, string, int, etc) are accepted as the in value.
|
||||||
|
func Marshal(in interface{}) (out []byte, err error) {
|
||||||
|
return yaml.Marshal(in)
|
||||||
|
}
|
||||||
2
common/helpers/yaml/testdata/1.yaml
vendored
Normal file
2
common/helpers/yaml/testdata/1.yaml
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
---
|
||||||
|
name: "1.yaml"
|
||||||
2
common/helpers/yaml/testdata/2.yaml
vendored
Normal file
2
common/helpers/yaml/testdata/2.yaml
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
---
|
||||||
|
name: "2.yaml"
|
||||||
6
common/helpers/yaml/testdata/base.yaml
vendored
Normal file
6
common/helpers/yaml/testdata/base.yaml
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
file1: !include 1.yaml
|
||||||
|
file2: !include 2.yaml
|
||||||
|
nested: !include nested.yaml
|
||||||
|
list1: !include list1.yaml
|
||||||
|
list2: !include list2.yaml
|
||||||
6
common/helpers/yaml/testdata/list1.yaml
vendored
Normal file
6
common/helpers/yaml/testdata/list1.yaml
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
# We cannot include a list, so we use a map with an empty key
|
||||||
|
"":
|
||||||
|
- el1
|
||||||
|
- el2
|
||||||
|
- el3
|
||||||
11
common/helpers/yaml/testdata/list2.yaml
vendored
Normal file
11
common/helpers/yaml/testdata/list2.yaml
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
|
||||||
|
.hidden:
|
||||||
|
- &squid
|
||||||
|
protocol: tcp
|
||||||
|
size: 1300
|
||||||
|
|
||||||
|
"":
|
||||||
|
- *squid
|
||||||
|
- el2
|
||||||
|
- el3
|
||||||
2
common/helpers/yaml/testdata/nested.yaml
vendored
Normal file
2
common/helpers/yaml/testdata/nested.yaml
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
---
|
||||||
|
file1: !include 1.yaml
|
||||||
80
common/helpers/yaml/unmarshal.go
Normal file
80
common/helpers/yaml/unmarshal.go
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2023 Free Mobile
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
// Package yaml implements YAML support for the Go language. It adds the ability
|
||||||
|
// to use the "!include" tag.
|
||||||
|
package yaml
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Unmarshal decodes the first document found within the in byte slice and
|
||||||
|
// assigns decoded values into the out value.
|
||||||
|
func Unmarshal(in []byte, out interface{}) (err error) {
|
||||||
|
return yaml.Unmarshal(in, out)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalWithInclude decodes the first document found within the in byte
|
||||||
|
// slice and assigns decoded values into the out value. It also accepts the
|
||||||
|
// "!include" tag to include additional files contained in the provided fs.
|
||||||
|
func UnmarshalWithInclude(fsys fs.FS, input string, out interface{}) (err error) {
|
||||||
|
var outNode yaml.Node
|
||||||
|
in, err := fs.ReadFile(fsys, input)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("cannot read %s: %w", input, err)
|
||||||
|
}
|
||||||
|
if err := Unmarshal(in, &outNode); err != nil {
|
||||||
|
return fmt.Errorf("in %s: %w", input, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if outNode.Kind == yaml.DocumentNode {
|
||||||
|
outNode = *outNode.Content[0]
|
||||||
|
}
|
||||||
|
if outNode.Kind == yaml.MappingNode {
|
||||||
|
// Remove hidden entries (prefixed with ".")
|
||||||
|
for i := 0; i < len(outNode.Content)-1; {
|
||||||
|
key := outNode.Content[i]
|
||||||
|
if key.Kind == yaml.ScalarNode && key.Tag == "!!str" && strings.HasPrefix(key.Value, ".") {
|
||||||
|
outNode.Content = outNode.Content[2:]
|
||||||
|
} else {
|
||||||
|
i += 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If we only have a 1-entry map whose key is empty, use the value
|
||||||
|
if len(outNode.Content) == 2 {
|
||||||
|
key := outNode.Content[0]
|
||||||
|
if key.Kind == yaml.ScalarNode && key.Tag == "!!str" && key.Value == "" {
|
||||||
|
outNode = *outNode.Content[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Walk the content nodes and replace them with the file they refer to.
|
||||||
|
todo := []*yaml.Node{&outNode}
|
||||||
|
for len(todo) > 0 {
|
||||||
|
current := todo[0]
|
||||||
|
todo = todo[1:]
|
||||||
|
if current.Tag != "!include" {
|
||||||
|
todo = append(todo, current.Content...)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if current.Alias != nil {
|
||||||
|
return fmt.Errorf("at line %d of %s, no alias is allowed for !include", current.Line, input)
|
||||||
|
}
|
||||||
|
if len(current.Content) > 0 {
|
||||||
|
return fmt.Errorf("at line %d of %s, no content is allowed for !include", current.Line, input)
|
||||||
|
}
|
||||||
|
var outNode yaml.Node
|
||||||
|
if err := UnmarshalWithInclude(fsys, current.Value, &outNode); err != nil {
|
||||||
|
return fmt.Errorf("at line %d of %s: %w", current.Line, input, err)
|
||||||
|
}
|
||||||
|
*current = outNode
|
||||||
|
}
|
||||||
|
|
||||||
|
return outNode.Decode(out)
|
||||||
|
}
|
||||||
37
common/helpers/yaml/unmarshal_test.go
Normal file
37
common/helpers/yaml/unmarshal_test.go
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2023 Free Mobile
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
package yaml_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"akvorado/common/helpers"
|
||||||
|
"akvorado/common/helpers/yaml"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestUnmarshalWithIn(t *testing.T) {
|
||||||
|
fsys := os.DirFS("testdata")
|
||||||
|
var got interface{}
|
||||||
|
if err := yaml.UnmarshalWithInclude(fsys, "base.yaml", &got); err != nil {
|
||||||
|
t.Fatalf("UnmarshalWithInclude() error:\n%+v", err)
|
||||||
|
}
|
||||||
|
expected := gin.H{
|
||||||
|
"file1": gin.H{"name": "1.yaml"},
|
||||||
|
"file2": gin.H{"name": "2.yaml"},
|
||||||
|
"nested": gin.H{
|
||||||
|
"file1": gin.H{"name": "1.yaml"},
|
||||||
|
},
|
||||||
|
"list1": []string{"el1", "el2", "el3"},
|
||||||
|
"list2": []interface{}{gin.H{
|
||||||
|
"protocol": "tcp",
|
||||||
|
"size": 1300,
|
||||||
|
}, "el2", "el3"},
|
||||||
|
}
|
||||||
|
if diff := helpers.Diff(got, expected); diff != "" {
|
||||||
|
t.Fatalf("UnmarshalWithInclude() (-got, +want):\n%s", diff)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -28,7 +28,7 @@ Once running, *Akvorado* web interface should be running on port 8081. A few
|
|||||||
synthetic flows are generated in the background. To disable them:
|
synthetic flows are generated in the background. To disable them:
|
||||||
|
|
||||||
1. Remove `:docker-compose-demo.yml` from `.env`,
|
1. Remove `:docker-compose-demo.yml` from `.env`,
|
||||||
2. Remove the associated configuration at the end of `akvorado.yaml`, and
|
2. Comment the last line of `akvorado.yaml`, and
|
||||||
3. Run `docker-compose up -d --remove-orphans`.
|
3. Run `docker-compose up -d --remove-orphans`.
|
||||||
|
|
||||||
If you want to send you own flows, the inlet is accepting both NetFlow
|
If you want to send you own flows, the inlet is accepting both NetFlow
|
||||||
|
|||||||
@@ -11,6 +11,10 @@ identified with a specific icon:
|
|||||||
- 🩹: bug fix
|
- 🩹: bug fix
|
||||||
- 🌱: miscellaneous change
|
- 🌱: miscellaneous change
|
||||||
|
|
||||||
|
## Unreleased
|
||||||
|
|
||||||
|
- 🌱 *common*: accept an `!include` tag to include other YAML files in `akvorado.yaml`
|
||||||
|
|
||||||
## 1.7.1 - 2023-01-27
|
## 1.7.1 - 2023-01-27
|
||||||
|
|
||||||
This is an important bugfix release. `DstNet*` values were classified using the
|
This is an important bugfix release. `DstNet*` values were classified using the
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"gopkg.in/yaml.v3"
|
|
||||||
|
"akvorado/common/helpers/yaml"
|
||||||
|
|
||||||
"akvorado/common/helpers"
|
"akvorado/common/helpers"
|
||||||
"akvorado/inlet/flow/input/file"
|
"akvorado/inlet/flow/input/file"
|
||||||
|
|||||||
Reference in New Issue
Block a user