mirror of
https://github.com/gravitl/netmaker.git
synced 2026-10-12 02:15:06 +00:00
* wip(go): return auth token with user on create org owner; * wip(go): prevent use of default tenant slug ; * wip(go): upsert settings for tenant in ctx; * wip(go): use passed ctx when updating user; remove password validation from ValidateUser (already validated in UpdateUser); * wip(go): qualify all tenant id usages with table name; * wip(go): use passed ctx * wip(go): return old enrollment key type on create; * wip(go): prevent null networks return; * wip(go): wire ctx in dns/nameserver functions; wire ctx in host registration functions; * wip(go): wire ctx in node functions; * wip(go): wire ctx in node functions; * wip(go): wire ctx in extclient functions; * wip(go): remove not needed field; * wip(go): use passed ctx; * wip(go): use unique index instead of primary key; * wip(go): wire ctx in extclient apis; * wip(go): wire ctx in extclient apis; * wip(go): remove org id check from global scoped get tenant api; * wip(go): add scope slug to discover response; * wip(go): wire ctx in get users; * wip(go): set tenant id in posture check violations; * wip(go): upsert membership instead of user; * wip(go): pass correct len; * wip(go): optimize (single loop); * wip(go): unify todos; * wip(go): add todo; * wip(go): wire context for network get; * wip(go): wire context; * wip(go): wire context; * wip(go): wire ctx when getting tenant superadmin; * wip(go): add network creator to network admin group; * wip(go): check for user membership on sync; * wip(go): add methods with strict membership check; * wip(go): remove unwanted feature flags; * wip(go): report per-tenant usage during license validation; * wip(go): move email setting from tenant to org; * wip(go): pass org scope to email init; * wip(go): remove old tenant email settings usages; use org settings to get email settings * wip(go): use get email settings from org settings; * wip(go): remove email settings migration; * wip(go): migrate email settings from server to org settings; * wip(go): assign global network admin group membership only for super-admin and admins; * wip(go): assign global network admin group membership only for super-admin and admins; * wip(go): add membership alias to filter; * wip(go): skip clearing local license validation response cache; * wip(go): extend license validation response for multi-tenancy; * wip(go): add functions to get sole tenant and org; * wip(go): use tenant-specific feature flags; * wip(go): add tenant status type; * wip(go): remove old hook comment; * wip(go): expect ctx during license validation; * wip(go): always create default org and tenant for ce; * wip(go): add tenant-specific check for license validation error; * wip(go): cache license validation response in memory; * wip(go): add todo to handle multiple-tenant for integration pull; * wip(go): pass ctx during license validation; * wip(go): add todo for making changes later; run hook separately for each tenant; * wip(go): return specific errors when license validation response not in cache; * wip(go): use retryable.httpclient for calling license validation api; * wip(go): process license validation; * wip(go): license validation function; * wip(go): migration on license validation; * wip(go): org settings not expected; * wip(go): remove expiry from license validation response; * wip(go): add limits and limits enforcement to license validation response; * wip(go): remove expiry usages; * wip(go): add arg to clear cache; * wip(go): add arg to clear cache; * wip(go): skip license validation if cached resp; * wip(go): allow org_id and tenant_id query params; * wip(go): upsert tenant membership on sync; * wip(go): pass ctx to delete network roles; * wip(go): create tenant membership on org owner creation on ce; * wip(go): add tenant orchestrator; * wip(go): use tenant orchestrator; * wip(go): add default settings for tenant; * wip(go): make org owner superadmin on all tenants; * wip(go): simplify SyncOrgAndTenants; * wip(go): retry license validation only 3 times * wip(go): store invalid err; * wip(go): add function to check if limits are to be enforced on a tenant; * wip(go): pass tenant scope if possible when checking for license validation error; * wip(go): remove merge errors; * wip(go): add functions for limit checks; * wip(go): wire host limit check; * wip(go): wire ingress limit check; * wip(go): wire egress limit check; * wip(go): wire client limit check; * wip(go): wire network limit check; * wip(go): wire user limit check; * wip(go): use correct errors; * wip(go): skip telemetry for msps; * wip(go): disable telemetry on msp tenants; * wip(go): err check; * wip(go): uncomment log event; * wip(go): get sso state to get scope for non-headless oauth login; * wip(go): inline delete pending user; * wip(go): allow both org and tenant scope for pending users table; * wip(go): add migration for pending user table during set tenant id and rekey org/tenant id; * wip(go): update queries to use new scope fields in pending users table; * wip(go): allow both org and tenant scope for user invites table; * wip(go): update queries to use new scope fields; * wip(go): add migration for rekey-ing org/tenant id and setting tenant id; * wip(go): inline delete user invite; * wip(go): set scope when creating invite; * wip(go): get user count with membership is ctx is tenant scoped; * wip(go): add methods to upsert and delete org memberships; * wip(go): add global valid tenant and org roles map; * wip(go): add scope query in user invite get by email; * wip(go): add support for upsert and delete of org and tenant membership both; * wip(go): infer scope for user invite apis; * wip(go): wire ctx in get user invite by email; * wip(go): allow no scope headers to be passed in infer scope apis; * wip(go): add validation and checks for org-scoped invite api handlers; * wip(go): wire ctx to is pending user check; * wip(go): infer scope for pending user apis; * wip(go): set default role based on ctx scope; * wip(go): move mfa to tenant membership table; move account status to membership tables; * wip(go): migrate account status and mfa settings; * wip(go): update account status on sync; * wip(go): use update mfa to update mfa setting; * wip(go): set new membership settings on user creation; * wip(go): use membership where required; * wip(go): wire ctx on key unlink refs; * wip(go): use r.Context directly without reinitializing db; * wip(go): wire ctx in acls; * wip(go): add tenant scoped primary key constructor; * wip(go): use tenant scoped primary key for acls, dns, extclients and tags; * wip(go): wire ctx for get groups in network; * wip(go): wire ctx for get groups; * wip(go): scope non-uuid group ids by tenant id; * wip(go): migrate non-uuid group ids to scoped ids; * wip(go): don't expect scope id in invite validation and signup apis; * wip(go): wire ctx for get matching user; allow org scope when querying by external idp id; * wip(go): add mfa to org; * wip(go): scope preauth token; * wip(go): add fallback for older auth tokens; * wip(go): wire ctx for preauth token creation; * wip(go): migrate mfa settings; * wip(go): resolve mfa settings for inherited auth; * wip(go): update mfa for org; * wip(go): infer scope for totp apis; * wip(go): use ctx when passed; * wip(go): infer scope for list user apis; * wip(go): ensure set primary keys don't cause errors during fetch; * wip(go): make primary key for integrations uuid and store provider in separate key; * wip(go): migrate integration ids; * wip(go): use provider instead of id everywhere; * wip(go): remove gorm column; * wip(go): wire ctx for igw egress creation; * wip(go): wire ctx for igw egress update; * wip(go): wire ctx for host registration; * wip(go): wire ctx for host registration; * wip(go): merge errors; * wip(go): merge errors; * wip(go): wire ctx; remove default scope usages; * wip(go): use get with membership; * wip(go): org scope license validation; * wip(go): remove debug log; * wip(go): remove scoping on list roles; * wip(go): ignore invite creation if already exists; * wip(go): add is msp func to check if deployment is msp deployment; * wip(go): ensure username is email for msp users; * wip(go): add email validated check on user table; * wip(go): mark email validated when oauth user; * wip(go): handle gorm error; * wip(go): add tenant id to siem grpc schema; * wip(go): read tenant from scoped ctx; * wip(go): pass scoped ctx to siem grpc client; * wip(go): remove unused publisher; * wip(go): publish all tenant exporter updates on pull; * wip(go): fix wg usage; * wip(go): tenant scope the ctx when getting server info; * wip(go): add tenant id to enrollment key token; * wip(go): make host register tenant scope; * wip(go): add default settings; * wip(go): use correct checks for is msp tenant; * wip(go): add email validation extension; * wip(go): add pages for validation check; * wip(go): use extension for validating user; * wip(go): add invite type; * wip(go): create only one validation invite per user email; * wip(go): add validate email handler; * wip(go): add email builder; * wip(go): add user invite type migration logic; * wip(go): only log email send failures; * wip(go): add tenant id to flows table; * wip(go): add func to check if connected to clickhouse; * wip(go): migrate clickhouse; * wip(go): add tenant id to mdm and edr state; * wip(go): add delete methods for tables; * wip(go): add tenant teardown method; * wip(go): handle tenant deletion; * wip(go): clean up flow logs on tenant deletion; * wip(go): add update org membership role id method; * wip(go): add transfer org ownership api; * wip(go): move audit logs retention period to org settings; * wip(go):get retention period from org settings; * wip(go): remove old audit logs usage; * wip(go): migrate audit logs retention period; * wip(go): unmarshal decodes nums as float64; * wip(go): run flow logs cleanup for all tenants in one go; * wip(go): add audit logs retention period and smtp settings to tenant settings table for non-msp tenants; * wip(go): resolve retention period and smtp settings correctly; * wip(go): handle retention period and smtp settings updates and fetches correctly; * wip(go): overlay retention period and smtp settings on server settings;; * wip(go): upsert overlayed settings; * wip(go): add azure tenant id to org settings; * wip(go): tenant scope list roles; * wip(go): add noop creds; * wip(go): use first instead of find; * wip(go): use correct roles when transfering ownership; * wip(go): delete access tokens only if tenant scoped; * wip(go): make delete user work for both org and tenant scope; * wip(go): delete extclients only if tenant scoped; * wip(go): check if caller is allowed to delete user; * wip(go): infer scope for update user; * wip(go): prevent org-owner elevation; * wip(go): permissions check for update; * wip(go): delete user access tokens only if tenant scope; * wip(go): delete extclients only if tenant scope; * wip(go): move upsert membership in upsert user; * wip(go): set api host when constructing server config; * wip(go): fix static errors; * wip(go): fix test cases; * wip(go): use correct get ns order; * wip(go): use correct get pending host order; * wip(go): use correct get access token order; * wip(go): use correct get event order; * wip(go): return error response on emqx user creation error; * wip(go): store correct value in cache; * wip(go): return better error response; * wip(go): return better error response; * wip(go): use cache when listing egress acls; * wip(go): wire ctx in UserHasNetworkGroupAccess; * wip(go): remove double scope wrapping; * wip(go): add security check for list and get org; * wip(go): ratelimit discover api; * wip(go): expect sole org id in get and create org owner; * wip(go): wrap create org owner in tx;
226 lines
7.6 KiB
Go
226 lines
7.6 KiB
Go
package mq
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
"time"
|
|
|
|
mqtt "github.com/eclipse/paho.mqtt.golang"
|
|
"github.com/gravitl/netmaker/db"
|
|
"github.com/gravitl/netmaker/logger"
|
|
"github.com/gravitl/netmaker/logic"
|
|
"github.com/gravitl/netmaker/schema"
|
|
"github.com/gravitl/netmaker/scope"
|
|
"github.com/gravitl/netmaker/servercfg"
|
|
"golang.org/x/exp/slog"
|
|
)
|
|
|
|
// KEEPALIVE_TIMEOUT - time in seconds for timeout
|
|
const KEEPALIVE_TIMEOUT = 60 //timeout in seconds
|
|
// MQ_DISCONNECT - disconnects MQ
|
|
const MQ_DISCONNECT = 250
|
|
|
|
// MQ_TIMEOUT - timeout for MQ
|
|
const MQ_TIMEOUT = 30
|
|
|
|
var peer_force_send = 0
|
|
|
|
var mqclient mqtt.Client
|
|
|
|
func setMqOptions(user, password string, opts *mqtt.ClientOptions) {
|
|
broker, _ := servercfg.GetMessageQueueEndpoint()
|
|
opts.AddBroker(broker)
|
|
opts.ClientID = logic.RandomString(23)
|
|
opts.SetUsername(user)
|
|
opts.SetPassword(password)
|
|
opts.SetAutoReconnect(true)
|
|
opts.SetConnectRetry(true)
|
|
opts.SetCleanSession(true)
|
|
opts.SetConnectRetryInterval(time.Second * 1)
|
|
opts.SetKeepAlive(time.Second * 15)
|
|
opts.SetOrderMatters(false)
|
|
opts.SetWriteTimeout(time.Minute)
|
|
}
|
|
|
|
// SetupMQTT creates a connection to broker and return client
|
|
func SetupMQTT(fatal bool) {
|
|
if servercfg.GetBrokerType() == servercfg.EmqxBrokerType {
|
|
if emqx.GetType() == servercfg.EmqxOnPremDeploy {
|
|
time.Sleep(10 * time.Second) // wait for the REST endpoint to be ready
|
|
// setup authenticator and create admin user
|
|
if err := emqx.CreateEmqxDefaultAuthenticator(); err != nil {
|
|
logger.Log(0, err.Error())
|
|
}
|
|
emqx.DeleteEmqxUser(servercfg.GetMqUserName())
|
|
if err := emqx.CreateEmqxUserforServer(); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
// create an ACL authorization source for the built in EMQX MNESIA database
|
|
if err := emqx.CreateEmqxDefaultAuthorizer(); err != nil {
|
|
logger.Log(0, err.Error())
|
|
}
|
|
// create a default deny ACL to all topics for all users
|
|
if err := emqx.CreateDefaultAllowRule(); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
} else {
|
|
emqx.DeleteEmqxUser(servercfg.GetMqUserName())
|
|
if err := emqx.CreateEmqxUserforServer(); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
opts := mqtt.NewClientOptions()
|
|
setMqOptions(servercfg.GetMqUserName(), servercfg.GetMqPassword(), opts)
|
|
logger.Log(0, "Mq Client Connecting with Random ID: ", opts.ClientID)
|
|
opts.SetOnConnectHandler(func(client mqtt.Client) {
|
|
// Only master pod subscribes to incoming client messages in HA setup
|
|
// This prevents duplicate message processing across multiple pods
|
|
// Worker pods can still publish messages but won't process incoming ones
|
|
serverName := servercfg.GetServer()
|
|
if servercfg.IsMasterPod() {
|
|
if token := client.Subscribe(fmt.Sprintf("update/%s/#", serverName), 0, mqtt.MessageHandler(UpdateNode)); token.WaitTimeout(MQ_TIMEOUT*time.Second) && token.Error() != nil {
|
|
logger.Log(0, "node update subscription failed")
|
|
}
|
|
if token := client.Subscribe(fmt.Sprintf("host/serverupdate/%s/#", serverName), 0, mqtt.MessageHandler(UpdateHost)); token.WaitTimeout(MQ_TIMEOUT*time.Second) && token.Error() != nil {
|
|
logger.Log(0, "host update subscription failed")
|
|
}
|
|
if token := client.Subscribe(fmt.Sprintf("signal/%s/#", serverName), 0, mqtt.MessageHandler(ClientPeerUpdate)); token.WaitTimeout(MQ_TIMEOUT*time.Second) && token.Error() != nil {
|
|
logger.Log(0, "node client subscription failed")
|
|
}
|
|
if token := client.Subscribe(fmt.Sprintf("metrics/%s/#", serverName), 0, mqtt.MessageHandler(UpdateMetrics)); token.WaitTimeout(MQ_TIMEOUT*time.Second) && token.Error() != nil {
|
|
logger.Log(0, "node metrics subscription failed")
|
|
}
|
|
if token := client.Subscribe(fmt.Sprintf("integration/%s/pull", serverName), 0, mqtt.MessageHandler(HandleExporterIntegrationPull)); token.WaitTimeout(MQ_TIMEOUT*time.Second) && token.Error() != nil {
|
|
logger.Log(0, "exporter integration pull subscription failed")
|
|
}
|
|
logger.Log(0, "MQ subscriptions established (master pod)")
|
|
} else {
|
|
logger.Log(0, "MQ publish-only mode (worker pod)")
|
|
}
|
|
if servercfg.IsHA() {
|
|
if token := client.Subscribe(fmt.Sprintf("serversync/%s", serverName), 0, mqtt.MessageHandler(handleServerSync)); token.WaitTimeout(MQ_TIMEOUT*time.Second) && token.Error() != nil {
|
|
logger.Log(0, "server sync subscription failed")
|
|
}
|
|
}
|
|
|
|
opts.SetOrderMatters(false)
|
|
opts.SetResumeSubs(true)
|
|
})
|
|
opts.SetConnectionLostHandler(func(c mqtt.Client, e error) {
|
|
slog.Warn("detected broker connection lost, auto-reconnect will retry", "err", e.Error())
|
|
})
|
|
mqclient = mqtt.NewClient(opts)
|
|
tperiod := time.Now().Add(10 * time.Second)
|
|
for {
|
|
if token := mqclient.Connect(); !token.WaitTimeout(MQ_TIMEOUT*time.Second) || token.Error() != nil {
|
|
logger.Log(2, "unable to connect to broker, retrying ...")
|
|
if time.Now().After(tperiod) {
|
|
if token.Error() == nil {
|
|
if fatal {
|
|
logger.FatalLog("could not connect to broker, token timeout, exiting ...")
|
|
}
|
|
logger.Log(0, "could not connect to broker, token timeout, exiting ...")
|
|
|
|
} else {
|
|
if fatal {
|
|
logger.FatalLog("could not connect to broker, exiting ...", token.Error().Error())
|
|
}
|
|
logger.Log(0, "could not connect to broker, exiting ...", token.Error().Error())
|
|
}
|
|
}
|
|
} else {
|
|
break
|
|
}
|
|
time.Sleep(2 * time.Second)
|
|
}
|
|
InitServerSync()
|
|
}
|
|
|
|
const CHECKIN_FLUSH_INTERVAL = 30
|
|
|
|
// normalizedMetricsExportInterval applies the same minimum as before (invalid/too-small
|
|
// intervals use a 10-minute default).
|
|
func normalizedMetricsExportInterval(ctx context.Context) time.Duration {
|
|
d := logic.GetMetricIntervalInMinutes(ctx)
|
|
if d < time.Minute {
|
|
return time.Minute * 10
|
|
}
|
|
return d
|
|
}
|
|
|
|
// runTenantMetricsExporter runs the metrics-export ticker for a single tenant, resetting
|
|
// it whenever that tenant's metric interval setting changes, until ctx is done.
|
|
func runTenantMetricsExporter(ctx context.Context) {
|
|
metricIntervalReset := logic.SubscribeMetricExportIntervalReset(ctx)
|
|
metricsTicker := time.NewTicker(normalizedMetricsExportInterval(ctx))
|
|
defer metricsTicker.Stop()
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
return
|
|
case <-metricsTicker.C:
|
|
PushAllMetricsToExporter(ctx)
|
|
case <-metricIntervalReset:
|
|
metricsTicker.Stop()
|
|
metricsTicker = time.NewTicker(normalizedMetricsExportInterval(ctx))
|
|
}
|
|
}
|
|
}
|
|
|
|
// Keepalive -- periodically pings all nodes to let them know server is still alive and doing well
|
|
func Keepalive(ctx context.Context) {
|
|
tenants, err := (&schema.Tenant{}).List(db.WithContext(ctx))
|
|
if err != nil {
|
|
slog.Error("failed to list tenants for peer update workers", "error", err)
|
|
}
|
|
for _, tenant := range tenants {
|
|
tenantCtx := scope.WithContext(db.WithContext(ctx), scope.TenantScope, tenant.ID)
|
|
warmPeerCaches(tenantCtx)
|
|
StartPeerUpdateWorker(tenantCtx)
|
|
go PublishPeerUpdate(tenantCtx, true)
|
|
go runTenantMetricsExporter(tenantCtx)
|
|
}
|
|
if servercfg.CacheEnabled() {
|
|
checkinTicker := time.NewTicker(CHECKIN_FLUSH_INTERVAL * time.Second)
|
|
defer checkinTicker.Stop()
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
logic.FlushNodeCheckins()
|
|
return
|
|
case <-time.After(time.Second * KEEPALIVE_TIMEOUT):
|
|
sendPeers()
|
|
case <-checkinTicker.C:
|
|
logic.FlushNodeCheckins()
|
|
}
|
|
}
|
|
} else {
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
return
|
|
case <-time.After(time.Second * KEEPALIVE_TIMEOUT):
|
|
sendPeers()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// IsConnected - function for determining if the mqclient is connected or not
|
|
func IsConnected() bool {
|
|
return mqclient != nil && mqclient.IsConnected()
|
|
}
|
|
|
|
// IsConnectionOpen - function for determining if the mqclient is connected or not
|
|
func IsConnectionOpen() bool {
|
|
return mqclient != nil && mqclient.IsConnectionOpen()
|
|
}
|
|
|
|
// CloseClient - function to close the mq connection from server
|
|
func CloseClient() {
|
|
mqclient.Disconnect(250)
|
|
}
|