quality / commitlint (push) Skipped
quality / changes (push) Successful in 9s
quality / docker-check (push) Skipped
quality / openapi (push) Successful in 46s
quality / web (push) Successful in 1m16s
quality / go (push) Successful in 2m42s
quality / bird2 (push) Successful in 16s
CD / quality (push) Successful in 5m19s
CD / publish (push) Successful in 7m19s
- Deleted unused components: `DashboardActivityTimeline`, `DashboardFramePanel`, `DashboardModulesGrid`, `DashboardRecentJobsGrid`, and `DashboardRecentRevisionsGrid` to streamline the dashboard. - Updated `DashboardKpiGrid` to improve KPI display logic, including progress indicators and enhanced badge functionality. - Refactored `DashboardNetworkHealth` to provide better status representation based on loading states and network conditions. - Introduced new properties for KPI cards to support progress tracking and improved visual feedback. This cleanup aims to enhance performance and maintainability of the dashboard while providing a better user experience.
149 lines
4.2 KiB
Go
149 lines
4.2 KiB
Go
package pipeline
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"net/netip"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"evobgp/internal/store"
|
|
|
|
"github.com/miekg/dns"
|
|
)
|
|
|
|
func loadModuleDohProfiles(st store.Backend, tenantID string, mod *store.Module) ([]*store.DohProfile, string, error) {
|
|
if mod == nil {
|
|
return nil, store.DohPolicyPrimaryOnly, nil
|
|
}
|
|
policy := store.NormalizeDohResolverPolicy(mod.DohResolverPolicy)
|
|
var profiles []*store.DohProfile
|
|
for _, id := range mod.EffectiveDohProfileIDs() {
|
|
prof, err := st.GetDohProfile(tenantID, id)
|
|
if err != nil {
|
|
return nil, "", fmt.Errorf("get doh profile %s: %w", id, err)
|
|
}
|
|
profiles = append(profiles, prof)
|
|
}
|
|
return profiles, policy, nil
|
|
}
|
|
|
|
func resolveDomainIPsWithPolicy(ctx context.Context, hc *http.Client, profiles []*store.DohProfile, policy, fqdn string) ([]netip.Addr, error) {
|
|
policy = store.NormalizeDohResolverPolicy(policy)
|
|
if len(profiles) == 0 {
|
|
return resolveDomainIPs(ctx, hc, nil, fqdn)
|
|
}
|
|
if len(profiles) == 1 {
|
|
return resolveDomainIPs(ctx, hc, profiles[0], fqdn)
|
|
}
|
|
|
|
switch policy {
|
|
case store.DohPolicyUnion:
|
|
return resolveDomainIPsUnion(ctx, hc, profiles, fqdn)
|
|
case store.DohPolicyFailover:
|
|
return resolveDomainIPsFailover(ctx, hc, profiles, fqdn)
|
|
default:
|
|
return resolveDomainIPs(ctx, hc, profiles[0], fqdn)
|
|
}
|
|
}
|
|
|
|
func resolveDomainIPsUnion(ctx context.Context, hc *http.Client, profiles []*store.DohProfile, fqdn string) ([]netip.Addr, error) {
|
|
var merged []netip.Addr
|
|
var errs []error
|
|
for _, prof := range profiles {
|
|
if prof == nil {
|
|
continue
|
|
}
|
|
ips, err := resolveDomainIPsNoSystemFallback(ctx, hc, prof, fqdn)
|
|
if err != nil {
|
|
errs = append(errs, fmt.Errorf("%s: %w", strings.TrimSpace(prof.URL), err))
|
|
continue
|
|
}
|
|
merged = append(merged, ips...)
|
|
}
|
|
merged = uniqAddrs(merged)
|
|
if len(merged) > 0 {
|
|
return merged, nil
|
|
}
|
|
if len(errs) > 0 {
|
|
return nil, fmt.Errorf("doh union failed: %v", errs)
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
func resolveDomainIPsFailover(ctx context.Context, hc *http.Client, profiles []*store.DohProfile, fqdn string) ([]netip.Addr, error) {
|
|
var lastErr error
|
|
for _, prof := range profiles {
|
|
if prof == nil {
|
|
continue
|
|
}
|
|
ips, err := resolveDomainIPsNoSystemFallback(ctx, hc, prof, fqdn)
|
|
if err != nil {
|
|
lastErr = err
|
|
continue
|
|
}
|
|
if len(ips) > 0 {
|
|
return ips, nil
|
|
}
|
|
}
|
|
if lastErr != nil {
|
|
return nil, lastErr
|
|
}
|
|
return resolveDomainIPs(ctx, hc, nil, fqdn)
|
|
}
|
|
|
|
// resolveDomainIPsNoSystemFallback queries one DoH profile without falling back to OS resolver.
|
|
func resolveDomainIPsNoSystemFallback(ctx context.Context, hc *http.Client, profile *store.DohProfile, fqdn string) ([]netip.Addr, error) {
|
|
host := strings.TrimSpace(strings.TrimSuffix(fqdn, "."))
|
|
if host == "" {
|
|
return nil, nil
|
|
}
|
|
if profile == nil || strings.TrimSpace(profile.URL) == "" {
|
|
return nil, fmt.Errorf("empty doh profile")
|
|
}
|
|
|
|
timeout := dohProfileTimeout(profile)
|
|
dctx, cancel := context.WithTimeout(ctx, timeout)
|
|
defer cancel()
|
|
|
|
baseURL := strings.TrimSpace(profile.URL)
|
|
v4, v6, err4, err6 := resolveDOHMessagePair(dctx, hc, baseURL, host)
|
|
if err4 != nil {
|
|
v4, err4 = resolveDomainWithDOHJSON(dctx, hc, baseURL, host, "A")
|
|
}
|
|
if err6 != nil {
|
|
v6, err6 = resolveDomainWithDOHJSON(dctx, hc, baseURL, host, "AAAA")
|
|
}
|
|
if err4 != nil && err6 != nil {
|
|
return nil, fmt.Errorf("doh failed for A and AAAA: %v; %v", err4, err6)
|
|
}
|
|
return uniqAddrs(append(v4, v6...)), nil
|
|
}
|
|
|
|
// resolveDOHMessagePair issues RFC8484 dns-message A and AAAA queries concurrently
|
|
// and waits for both (fallbacks are handled by the caller).
|
|
func resolveDOHMessagePair(ctx context.Context, hc *http.Client, baseURL, host string) (v4, v6 []netip.Addr, err4, err6 error) {
|
|
var wg sync.WaitGroup
|
|
wg.Add(2)
|
|
go func() {
|
|
defer wg.Done()
|
|
v4, err4 = resolveDomainWithDOHMessage(ctx, hc, baseURL, host, dns.TypeA)
|
|
}()
|
|
go func() {
|
|
defer wg.Done()
|
|
v6, err6 = resolveDomainWithDOHMessage(ctx, hc, baseURL, host, dns.TypeAAAA)
|
|
}()
|
|
wg.Wait()
|
|
return v4, v6, err4, err6
|
|
}
|
|
|
|
func dohProfileTimeout(profile *store.DohProfile) time.Duration {
|
|
timeout := 10 * time.Second
|
|
if profile != nil && profile.TimeoutMs != nil && *profile.TimeoutMs > 0 {
|
|
timeout = time.Duration(*profile.TimeoutMs) * time.Millisecond
|
|
}
|
|
return timeout
|
|
}
|