mirror of
https://github.com/netbirdio/netbird.git
synced 2026-05-21 08:09:55 +00:00
feat(reverse-proxy): clusters API surfaces type, online status, and capability flags (#6148)
The cluster listing now answers three questions in one round-trip instead of forcing the dashboard to cross-reference the domains API: which clusters can this account see, are they currently up, and what do they support. The ProxyCluster wire type drops the boolean self_hosted in favour of a `type` enum (`account` / `shared`) plus explicit `online`, `supports_custom_ports`, `require_subdomain`, and `supports_crowdsec` fields. Store query reworked so offline clusters still appear (no last_seen WHERE), with online and connected_proxies both derived from the existing 2-min active window via portable CASE expressions; the 1-hour heartbeat reaper still removes long-stale rows. Service manager enriches each cluster with the capability flags via the existing per-cluster lookups (CapabilityProvider now also exposes ClusterSupportsCrowdSec). GetActiveClusterAddresses* keep their tight 2-min filter so service routing and domain enumeration aren't pulled into the wider window. The hard cut removes self_hosted from the response — the dashboard is the only consumer and is updated in the matching PR; no transitional field is shipped. Adds a cross-engine regression test asserting offline clusters surface, connected_proxies counts only fresh proxies, and account-scoped BYOP clusters never leak across accounts.
This commit is contained in:
@@ -3417,19 +3417,43 @@ components:
|
||||
type: string
|
||||
description: Cluster address used for CNAME targets
|
||||
example: "eu.proxy.netbird.io"
|
||||
type:
|
||||
$ref: '#/components/schemas/ProxyClusterType'
|
||||
online:
|
||||
type: boolean
|
||||
description: Whether at least one proxy in the cluster has heartbeated within the active window
|
||||
example: true
|
||||
connected_proxies:
|
||||
type: integer
|
||||
description: Number of proxy nodes connected in this cluster
|
||||
description: Number of proxy nodes currently connected (heartbeat within the active window)
|
||||
example: 3
|
||||
self_hosted:
|
||||
supports_custom_ports:
|
||||
type: boolean
|
||||
description: Whether this cluster is a self-hosted (BYOP) proxy managed by the account owner
|
||||
description: Whether the cluster supports binding arbitrary TCP/UDP ports
|
||||
example: true
|
||||
require_subdomain:
|
||||
type: boolean
|
||||
description: Whether services on this cluster must include a subdomain label
|
||||
example: false
|
||||
supports_crowdsec:
|
||||
type: boolean
|
||||
description: Whether all active proxies in the cluster have CrowdSec configured
|
||||
example: false
|
||||
required:
|
||||
- id
|
||||
- address
|
||||
- type
|
||||
- online
|
||||
- connected_proxies
|
||||
- self_hosted
|
||||
ProxyClusterType:
|
||||
type: string
|
||||
description: |
|
||||
Source of the proxy cluster. `account` clusters are owned and operated by the account (BYOP);
|
||||
`shared` clusters are operated by NetBird and shared across accounts.
|
||||
enum:
|
||||
- account
|
||||
- shared
|
||||
example: shared
|
||||
ReverseProxyDomainType:
|
||||
type: string
|
||||
description: Type of Reverse Proxy Domain
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package api provides primitives to interact with the openapi HTTP API.
|
||||
//
|
||||
// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.6.0 DO NOT EDIT.
|
||||
// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.7.0 DO NOT EDIT.
|
||||
package api
|
||||
|
||||
import (
|
||||
@@ -13,8 +13,8 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
BearerAuthScopes = "BearerAuth.Scopes"
|
||||
TokenAuthScopes = "TokenAuth.Scopes"
|
||||
BearerAuthScopes bearerAuthContextKey = "BearerAuth.Scopes"
|
||||
TokenAuthScopes tokenAuthContextKey = "TokenAuth.Scopes"
|
||||
)
|
||||
|
||||
// Defines values for AccessRestrictionsCrowdsecMode.
|
||||
@@ -511,6 +511,7 @@ func (e GroupMinimumIssued) Valid() bool {
|
||||
|
||||
// Defines values for IdentityProviderType.
|
||||
const (
|
||||
IdentityProviderTypeAdfs IdentityProviderType = "adfs"
|
||||
IdentityProviderTypeEntra IdentityProviderType = "entra"
|
||||
IdentityProviderTypeGoogle IdentityProviderType = "google"
|
||||
IdentityProviderTypeMicrosoft IdentityProviderType = "microsoft"
|
||||
@@ -518,12 +519,13 @@ const (
|
||||
IdentityProviderTypeOkta IdentityProviderType = "okta"
|
||||
IdentityProviderTypePocketid IdentityProviderType = "pocketid"
|
||||
IdentityProviderTypeZitadel IdentityProviderType = "zitadel"
|
||||
IdentityProviderTypeAdfs IdentityProviderType = "adfs"
|
||||
)
|
||||
|
||||
// Valid indicates whether the value is a known member of the IdentityProviderType enum.
|
||||
func (e IdentityProviderType) Valid() bool {
|
||||
switch e {
|
||||
case IdentityProviderTypeAdfs:
|
||||
return true
|
||||
case IdentityProviderTypeEntra:
|
||||
return true
|
||||
case IdentityProviderTypeGoogle:
|
||||
@@ -538,8 +540,6 @@ func (e IdentityProviderType) Valid() bool {
|
||||
return true
|
||||
case IdentityProviderTypeZitadel:
|
||||
return true
|
||||
case IdentityProviderTypeAdfs:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
@@ -878,6 +878,24 @@ func (e PolicyRuleUpdateProtocol) Valid() bool {
|
||||
}
|
||||
}
|
||||
|
||||
// Defines values for ProxyClusterType.
|
||||
const (
|
||||
ProxyClusterTypeAccount ProxyClusterType = "account"
|
||||
ProxyClusterTypeShared ProxyClusterType = "shared"
|
||||
)
|
||||
|
||||
// Valid indicates whether the value is a known member of the ProxyClusterType enum.
|
||||
func (e ProxyClusterType) Valid() bool {
|
||||
switch e {
|
||||
case ProxyClusterTypeAccount:
|
||||
return true
|
||||
case ProxyClusterTypeShared:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Defines values for ResourceType.
|
||||
const (
|
||||
ResourceTypeDomain ResourceType = "domain"
|
||||
@@ -1638,7 +1656,9 @@ type Checks struct {
|
||||
// OsVersionCheck Posture check for the version of operating system
|
||||
OsVersionCheck *OSVersionCheck `json:"os_version_check,omitempty"`
|
||||
|
||||
// PeerNetworkRangeCheck Posture check for allow or deny access based on the peer's IP addresses. A range matches when it contains any of the peer's local network interface IPs or its public connection (NAT egress) IP, so ranges may target private subnets, public CIDRs, or single hosts via a /32 or /128.
|
||||
// PeerNetworkRangeCheck Posture check for allow or deny access based on the peer's IP addresses. A range matches when it
|
||||
// contains any of the peer's local network interface IPs or its public connection (NAT egress) IP,
|
||||
// so ranges may target private subnets, public CIDRs, or single hosts via a /32 or /128.
|
||||
PeerNetworkRangeCheck *PeerNetworkRangeCheck `json:"peer_network_range_check,omitempty"`
|
||||
|
||||
// ProcessCheck Posture Check for binaries exist and are running in the peer’s system
|
||||
@@ -3330,7 +3350,9 @@ type PeerMinimum struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// PeerNetworkRangeCheck Posture check for allow or deny access based on the peer's IP addresses. A range matches when it contains any of the peer's local network interface IPs or its public connection (NAT egress) IP, so ranges may target private subnets, public CIDRs, or single hosts via a /32 or /128.
|
||||
// PeerNetworkRangeCheck Posture check for allow or deny access based on the peer's IP addresses. A range matches when it
|
||||
// contains any of the peer's local network interface IPs or its public connection (NAT egress) IP,
|
||||
// so ranges may target private subnets, public CIDRs, or single hosts via a /32 or /128.
|
||||
type PeerNetworkRangeCheck struct {
|
||||
// Action Action to take upon policy match
|
||||
Action PeerNetworkRangeCheckAction `json:"action"`
|
||||
@@ -3785,19 +3807,36 @@ type ProxyAccessLogsResponse struct {
|
||||
|
||||
// ProxyCluster A proxy cluster represents a group of proxy nodes serving the same address
|
||||
type ProxyCluster struct {
|
||||
// Id Unique identifier of a proxy in this cluster
|
||||
Id string `json:"id"`
|
||||
|
||||
// Address Cluster address used for CNAME targets
|
||||
Address string `json:"address"`
|
||||
|
||||
// ConnectedProxies Number of proxy nodes connected in this cluster
|
||||
// ConnectedProxies Number of proxy nodes currently connected (heartbeat within the active window)
|
||||
ConnectedProxies int `json:"connected_proxies"`
|
||||
|
||||
// SelfHosted Whether this cluster is a self-hosted (BYOP) proxy managed by the account owner
|
||||
SelfHosted bool `json:"self_hosted"`
|
||||
// Id Unique identifier of a proxy in this cluster
|
||||
Id string `json:"id"`
|
||||
|
||||
// Online Whether at least one proxy in the cluster has heartbeated within the active window
|
||||
Online bool `json:"online"`
|
||||
|
||||
// RequireSubdomain Whether services on this cluster must include a subdomain label
|
||||
RequireSubdomain *bool `json:"require_subdomain,omitempty"`
|
||||
|
||||
// SupportsCrowdsec Whether all active proxies in the cluster have CrowdSec configured
|
||||
SupportsCrowdsec *bool `json:"supports_crowdsec,omitempty"`
|
||||
|
||||
// SupportsCustomPorts Whether the cluster supports binding arbitrary TCP/UDP ports
|
||||
SupportsCustomPorts *bool `json:"supports_custom_ports,omitempty"`
|
||||
|
||||
// Type Source of the proxy cluster. `account` clusters are owned and operated by the account (BYOP);
|
||||
// `shared` clusters are operated by NetBird and shared across accounts.
|
||||
Type ProxyClusterType `json:"type"`
|
||||
}
|
||||
|
||||
// ProxyClusterType Source of the proxy cluster. `account` clusters are owned and operated by the account (BYOP);
|
||||
// `shared` clusters are operated by NetBird and shared across accounts.
|
||||
type ProxyClusterType string
|
||||
|
||||
// ProxyToken defines model for ProxyToken.
|
||||
type ProxyToken struct {
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
@@ -4820,6 +4859,12 @@ type ZoneRequest struct {
|
||||
// Conflict Standard error response. Note: The exact structure of this error response is inferred from `util.WriteErrorResponse` and `util.WriteError` usage in the provided Go code, as a specific Go struct for errors was not provided.
|
||||
type Conflict = ErrorResponse
|
||||
|
||||
// bearerAuthContextKey is the context key for BearerAuth security scheme
|
||||
type bearerAuthContextKey string
|
||||
|
||||
// tokenAuthContextKey is the context key for TokenAuth security scheme
|
||||
type tokenAuthContextKey string
|
||||
|
||||
// GetApiEventsNetworkTrafficParams defines parameters for GetApiEventsNetworkTraffic.
|
||||
type GetApiEventsNetworkTrafficParams struct {
|
||||
// Page Page number
|
||||
|
||||
Reference in New Issue
Block a user