Add native traffic inspection to Harbor Connect and Gateway
This commit is contained in:
@@ -40,6 +40,28 @@ const snapshot = {
|
||||
},
|
||||
domainTraffic: {
|
||||
observedAt,
|
||||
source: {
|
||||
error: null,
|
||||
mode: 'shadow',
|
||||
writer: 'snapshot',
|
||||
activeConnections: 4,
|
||||
native: {
|
||||
state: 'degraded',
|
||||
epoch: 'epoch-1',
|
||||
sequence: 7,
|
||||
observedAt,
|
||||
active: 5,
|
||||
unattributedUploadBytes: '11',
|
||||
unattributedDownloadBytes: '22',
|
||||
},
|
||||
shadow: {
|
||||
activeDifference: 1,
|
||||
uploadDifferenceBytes: '-30',
|
||||
downloadDifferenceBytes: '40',
|
||||
routeMismatches: 2,
|
||||
deviceMismatches: 3,
|
||||
},
|
||||
},
|
||||
overflowConnections: '2',
|
||||
attributionEvents: {
|
||||
unresolved_host: '3',
|
||||
@@ -97,6 +119,15 @@ test('Prometheus exposition keeps exact counters, stable identity and escaped na
|
||||
assert.match(output, /harbor_domain_traffic_attribution_events_total\{outcome="unresolved_host"\} 3/);
|
||||
assert.match(output, /harbor_domain_traffic_attribution_events_total\{outcome="unknown_device"\} 4/);
|
||||
assert.match(output, /harbor_domain_traffic_attribution_events_total\{outcome="unsupported_source"\} 5/);
|
||||
assert.match(output, /harbor_traffic_collector_info\{mode="shadow",writer="snapshot"\} 1/);
|
||||
assert.match(output, /harbor_traffic_collector_state\{state="degraded"\} 1/);
|
||||
assert.match(output, /harbor_traffic_collector_unattributed_bytes\{direction="download"\} 22/);
|
||||
assert.match(output, /harbor_traffic_collector_unattributed_bytes\{direction="upload"\} 11/);
|
||||
assert.match(output, /harbor_traffic_shadow_active_difference 1/);
|
||||
assert.match(output, /harbor_traffic_shadow_difference_bytes\{direction="download"\} 40/);
|
||||
assert.match(output, /harbor_traffic_shadow_difference_bytes\{direction="upload"\} -30/);
|
||||
assert.match(output, /harbor_traffic_shadow_route_mismatches 2/);
|
||||
assert.match(output, /harbor_traffic_shadow_device_mismatches 3/);
|
||||
assert.doesNotMatch(output, /harbor_device_domain_traffic_bytes_total\{[^\n]*name=/);
|
||||
assert.doesNotMatch(output, /harbor_device_(?:direct_ipv4_packet|singbox_tracked)_bytes_total\{[^\n]*(?:name|ip|mac|server)=/);
|
||||
assert.equal(output.endsWith('\n'), true);
|
||||
@@ -122,6 +153,15 @@ test('Prometheus response uses the negotiated legacy text contract without mutat
|
||||
assert.deepEqual(snapshot, before);
|
||||
});
|
||||
|
||||
test('legacy combined Gateway snapshots keep existing metrics without collector diagnostics', () => {
|
||||
const legacy = structuredClone(snapshot);
|
||||
legacy.domainTraffic.source = { error: null, activeConnections: 0 };
|
||||
const output = renderPrometheusMetrics(legacy);
|
||||
|
||||
assert.match(output, /harbor_singbox_tracked_bytes_total/);
|
||||
assert.doesNotMatch(output, /harbor_traffic_collector_info/);
|
||||
});
|
||||
|
||||
test('invalid canonical counters fail the scrape instead of publishing corrupt values', () => {
|
||||
const invalid = { traffic: { gatewayBytes: 'broken', proxyBytes: '0' }, devices: [] };
|
||||
assert.throws(
|
||||
@@ -135,6 +175,12 @@ test('invalid canonical counters fail the scrape instead of publishing corrupt v
|
||||
const invalidRoute = structuredClone(snapshot);
|
||||
invalidRoute.domainTraffic.routes[0].outbound = 'vpn-server-tag';
|
||||
assert.throws(() => renderPrometheusMetrics(invalidRoute), /Invalid sing-box outbound labels/);
|
||||
const invalidCollector = structuredClone(snapshot);
|
||||
invalidCollector.domainTraffic.source.mode = 'future';
|
||||
assert.throws(() => renderPrometheusMetrics(invalidCollector), /Invalid traffic collector labels/);
|
||||
const invalidShadow = structuredClone(snapshot);
|
||||
invalidShadow.domainTraffic.source.shadow.uploadDifferenceBytes = '1.5';
|
||||
assert.throws(() => renderPrometheusMetrics(invalidShadow), /Invalid Prometheus gauge/);
|
||||
});
|
||||
|
||||
function routeResponse() {
|
||||
|
||||
Reference in New Issue
Block a user