mirror of
https://github.com/akvorado/akvorado.git
synced 2025-12-12 06:24:10 +01:00
Fix #605 All MergeTree tables are now replicated. For some tables, a `_local` variant is added and the non-`_local` variant is now distributed. The distributed tables are the `flows` table, the `flows_DDDD` tables (where `DDDD` is a duration), as well as the `flows_raw_errors` table. The `exporters` table is not distributed and stays local. The data is following this schema: - data is coming from `flows_HHHH_raw` table, using the Kafka engine - the `flows_HHHH_raw_consumer` reads data from `flows_HHHH_raw` (local) and sends it to `flows` (distributed) when there is no error - the `flows_raw_errors_consumer` reads data from `flows_HHHH_raw` (local) and sends it to `flows_raw_errors` (distributed) - the `flows_DDDD_consumer` reads fata from `flows_local` (local) and sends it to `flow_DDDD_local` (local) - the `exporters_consumer` reads data from `flows` (distributed) and sends it to `exporters` (local) The reason for `flows_HHHH_raw_consumer` to send data to the distributed `flows` table, and not the local one is to ensure flows are balanced (for example, if there is not enough Kafka partitions). But sending it to `flows_local` would have been possible. On the other hand, it is important for `flows_DDDD_consumer` to read from local to avoid duplication. It could have sent to distributed, but the data is now balanced correctly and we just send it to local instead for better performance. The `exporters_consumer` is allowed to read from the distributed `flows` table because it writes the result to the local `exporters` table.
146 lines
3.8 KiB
Go
146 lines
3.8 KiB
Go
// SPDX-FileCopyrightText: 2023 Free Mobile
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
package clickhouse
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net"
|
|
"net/http"
|
|
"testing"
|
|
"time"
|
|
|
|
"akvorado/common/clickhousedb"
|
|
"akvorado/common/remotedatasourcefetcher"
|
|
"akvorado/orchestrator/geoip"
|
|
|
|
"akvorado/common/daemon"
|
|
"akvorado/common/helpers"
|
|
"akvorado/common/httpserver"
|
|
"akvorado/common/reporter"
|
|
"akvorado/common/schema"
|
|
)
|
|
|
|
func TestNetworkSources(t *testing.T) {
|
|
r := reporter.NewMock(t)
|
|
clickHouseComponent := clickhousedb.SetupClickHouse(t, r, false)
|
|
|
|
// Mux to answer requests
|
|
ready := make(chan bool)
|
|
mux := http.NewServeMux()
|
|
mux.Handle("/amazon.json", http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
|
select {
|
|
case <-ready:
|
|
default:
|
|
w.WriteHeader(404)
|
|
return
|
|
}
|
|
w.Header().Add("Content-Type", "application/json")
|
|
w.WriteHeader(200)
|
|
w.Write([]byte(`
|
|
{
|
|
"syncToken": "1665609189",
|
|
"createDate": "2022-10-12-21-13-09",
|
|
"prefixes": [
|
|
{
|
|
"ip_prefix": "3.2.34.0/26",
|
|
"region": "af-south-1",
|
|
"service": "AMAZON",
|
|
"network_border_group": "af-south-1"
|
|
}
|
|
],
|
|
"ipv6_prefixes": [
|
|
{
|
|
"ipv6_prefix": "2600:1ff2:4000::/40",
|
|
"region": "us-west-2",
|
|
"service": "AMAZON",
|
|
"network_border_group": "us-west-2"
|
|
},
|
|
{
|
|
"ipv6_prefix": "2600:1f14:fff:f800::/56",
|
|
"region": "us-west-2",
|
|
"service": "ROUTE53_HEALTHCHECKS",
|
|
"network_border_group": "us-west-2"
|
|
}
|
|
]
|
|
}
|
|
`))
|
|
}))
|
|
|
|
// Setup an HTTP server to serve the JSON
|
|
listener, err := net.Listen("tcp", "127.0.0.1:0")
|
|
if err != nil {
|
|
t.Fatalf("Listen() error:\n%+v", err)
|
|
}
|
|
server := &http.Server{
|
|
Addr: listener.Addr().String(),
|
|
Handler: mux,
|
|
}
|
|
address := listener.Addr()
|
|
go server.Serve(listener)
|
|
defer server.Shutdown(context.Background())
|
|
|
|
config := DefaultConfiguration()
|
|
config.SkipMigrations = true
|
|
config.NetworkSourcesTimeout = 10 * time.Millisecond
|
|
config.NetworkSources = map[string]remotedatasourcefetcher.RemoteDataSource{
|
|
"amazon": {
|
|
URL: fmt.Sprintf("http://%s/amazon.json", address),
|
|
Method: "GET",
|
|
Headers: map[string]string{
|
|
"X-Foo": "hello",
|
|
},
|
|
Timeout: 20 * time.Millisecond,
|
|
Interval: 100 * time.Millisecond,
|
|
Transform: remotedatasourcefetcher.MustParseTransformQuery(`
|
|
(.prefixes + .ipv6_prefixes)[] |
|
|
{ prefix: (.ip_prefix // .ipv6_prefix), tenant: "amazon", region: .region, role: .service|ascii_downcase }
|
|
`),
|
|
},
|
|
}
|
|
c, err := New(r, config, Dependencies{
|
|
Daemon: daemon.NewMock(t),
|
|
HTTP: httpserver.NewMock(t, r),
|
|
Schema: schema.NewMock(t),
|
|
GeoIP: geoip.NewMock(t, r, false),
|
|
ClickHouse: clickHouseComponent,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("New() error:\n%+v", err)
|
|
}
|
|
helpers.StartStop(t, c)
|
|
|
|
// When not ready, we get a 503
|
|
helpers.TestHTTPEndpoints(t, c.d.HTTP.LocalAddr(), helpers.HTTPEndpointCases{
|
|
{
|
|
Description: "try when not ready",
|
|
URL: "/api/v0/orchestrator/clickhouse/networks.csv",
|
|
StatusCode: 503,
|
|
},
|
|
})
|
|
close(ready)
|
|
time.Sleep(50 * time.Millisecond)
|
|
helpers.TestHTTPEndpoints(t, c.d.HTTP.LocalAddr(), helpers.HTTPEndpointCases{
|
|
{
|
|
Description: "try when ready",
|
|
URL: "/api/v0/orchestrator/clickhouse/networks.csv",
|
|
ContentType: "text/csv; charset=utf-8",
|
|
FirstLines: []string{
|
|
`network,name,role,site,region,country,state,city,tenant,asn`,
|
|
`3.2.34.0/26,,amazon,,af-south-1,,,,amazon,`,
|
|
`2600:1f14:fff:f800::/56,,route53_healthchecks,,us-west-2,,,,amazon,`,
|
|
`2600:1ff2:4000::/40,,amazon,,us-west-2,,,,amazon,`,
|
|
},
|
|
},
|
|
})
|
|
|
|
gotMetrics := r.GetMetrics("akvorado_common_remotedatasourcefetcher_data_")
|
|
expectedMetrics := map[string]string{
|
|
`total{source="amazon",type="network_source"}`: "3",
|
|
}
|
|
if diff := helpers.Diff(gotMetrics, expectedMetrics); diff != "" {
|
|
t.Fatalf("Metrics (-got, +want):\n%s", diff)
|
|
}
|
|
}
|