migrateverify

package
v0.8.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 26, 2026 License: Apache-2.0 Imports: 17 Imported by: 0

Documentation

Overview

Package migrateverify proves a migrated or shadow-running instance matches the source platform before cutover. It compares names only: env var values never enter a snapshot, a report or a log line.

Index

Constants

View Source
const (
	EnvProbeTimeout      = "APP_MIGRATE_VERIFY_PROBE_TIMEOUT"
	EnvProbeConcurrency  = "APP_MIGRATE_VERIFY_PROBE_CONCURRENCY"
	EnvAllowPrivateProbe = "APP_MIGRATE_VERIFY_ALLOW_PRIVATE_PROBES"
	EnvTLSWarnDays       = "APP_MIGRATE_VERIFY_TLS_WARN_DAYS"
	EnvLatencyFactor     = "APP_MIGRATE_VERIFY_LATENCY_FACTOR"
	EnvLatencyFloorMS    = "APP_MIGRATE_VERIFY_LATENCY_FLOOR_MS"
)

Env names that tune the probes and the thresholds that classify them.

View Source
const (
	DefaultProbeTimeout     = 10 * time.Second
	DefaultProbeConcurrency = 6
	MaxProbeTimeout         = 60 * time.Second
	MaxProbeConcurrency     = 32
)

Fallbacks used when the env var is unset or invalid.

View Source
const (
	VerdictPass = "pass"
	VerdictWarn = "warn"
	VerdictFail = "fail"
)

Verdicts of a whole report.

Variables

View Source
var ErrBlockedAddress = platformimport.ErrBlockedAddress

ErrBlockedAddress is returned when a probe would dial a private or loopback address.

Functions

func SameDomainFamily

func SameDomainFamily(a, b string) bool

SameDomainFamily reports whether two hosts share their last two labels (or are equal), so www and apex count as one family and another site does not.

func ValidDomain

func ValidDomain(d string) bool

ValidDomain accepts a plain hostname, never a URL, port, wildcard or path.

func ValidateAddr

func ValidateAddr(addr string) error

ValidateAddr checks a dial override: an IP, optionally with a port.

Types

type Category

type Category string

Category groups differences by the resource they concern.

const (
	CatApps      Category = "apps"
	CatDomains   Category = "domains"
	CatEnv       Category = "env"
	CatDatabases Category = "databases"
	CatVolumes   Category = "volumes"
	CatJobs      Category = "jobs"
	CatProbes    Category = "probes"
)

Difference categories.

type Comparison

type Comparison struct {
	Differences []Difference
	Totals      []Totals
	Matched     []MatchedApp
}

Comparison is the result of Compare: the differences, per-category totals and the pairs the live probes should run on.

func Compare

func Compare(src Source, tgt Target) Comparison

Compare classifies every difference between the source and this instance.

type Counts

type Counts struct {
	Blocking int `json:"blocking"`
	Warning  int `json:"warning"`
	Info     int `json:"info"`
}

Counts is the number of differences per severity.

type DB

type DB struct {
	Name    string
	Engine  string
	Version string
}

DB is a database on either side.

type Difference

type Difference struct {
	Category Category `json:"category"`
	Severity Severity `json:"severity"`
	App      string   `json:"app,omitempty"`
	Subject  string   `json:"subject"`
	Detail   string   `json:"detail"`
	Fix      string   `json:"fix"`
}

Difference is one mismatch with a one-line fix hint.

func CompareProbes

func CompareProbes(probes []DomainProbe, th Thresholds) []Difference

CompareProbes classifies the live probe results of every domain.

type DomainProbe

type DomainProbe struct {
	App    string      `json:"app"`
	Domain string      `json:"domain"`
	Staged bool        `json:"staged,omitempty"`
	Source ProbeResult `json:"source"`
	Target ProbeResult `json:"target"`
}

DomainProbe pairs both sides of one domain.

type Job

type Job struct {
	Name     string
	Schedule string
	Enabled  bool
}

Job is a scheduled command, identified by name and cron expression only.

type MatchedApp

type MatchedApp struct {
	Source SourceApp
	Target TargetApp
}

MatchedApp pairs a source app with its counterpart on this instance.

type Pair

type Pair struct {
	App    string
	Domain string
	Staged bool
}

Pair is one domain to probe on both sides.

type ProbeOptions

type ProbeOptions struct {
	Timeout     time.Duration
	Concurrency int
	// AllowPrivate lets probes reach private and loopback addresses. Metadata and link-local stay blocked.
	AllowPrivate bool
	// SourceAddr and TargetAddr, when set, are the IP (or ip:port) each side is dialed at while the
	// domain stays the Host and TLS name. Empty means normal DNS.
	SourceAddr string
	TargetAddr string
}

ProbeOptions configure a Prober.

func ClampProbeOptions

func ClampProbeOptions(o ProbeOptions) ProbeOptions

ClampProbeOptions applies defaults and upper bounds.

func ProbeOptionsFromEnv

func ProbeOptionsFromEnv(lookup func(string) (string, bool)) ProbeOptions

ProbeOptionsFromEnv reads the probe timeout and concurrency through lookup.

type ProbeResult

type ProbeResult struct {
	URL            string `json:"url"`
	Status         int    `json:"status,omitempty"`
	LatencyMS      int64  `json:"latency_ms,omitempty"`
	TLS            bool   `json:"tls"`
	TLSValid       bool   `json:"tls_valid"`
	TLSDaysLeft    int    `json:"tls_days_left,omitempty"`
	TLSError       string `json:"tls_error,omitempty"`
	RedirectTarget string `json:"redirect_target,omitempty"`
	// RedirectOffDomain is true when the redirect leaves the probed host's domain family. It is never followed.
	RedirectOffDomain bool   `json:"redirect_off_domain,omitempty"`
	Error             string `json:"error,omitempty"`
}

ProbeResult is what one side answered for a domain.

type Prober

type Prober struct {
	Opts ProbeOptions
}

Prober runs HTTP probes under the SSRF guard.

func (Prober) Probe

func (p Prober) Probe(ctx context.Context, domain, override string) ProbeResult

Probe requests https://domain/ and falls back to http when nothing answers TLS.

func (Prober) ProbeAll

func (p Prober) ProbeAll(ctx context.Context, pairs []Pair) []DomainProbe

ProbeAll probes every pair on both sides with bounded concurrency. Results keep the input order.

type Report

type Report struct {
	Platform    string        `json:"platform"`
	GeneratedAt time.Time     `json:"generated_at"`
	Verdict     string        `json:"verdict"`
	Counts      Counts        `json:"counts"`
	Categories  []Totals      `json:"categories"`
	Differences []Difference  `json:"differences"`
	Probes      []DomainProbe `json:"probes,omitempty"`
	Notes       []string      `json:"notes,omitempty"`
}

Report is the full parity report. It holds names, counts and probe results only.

func Build

func Build(ctx context.Context, src Source, tgt Target, prober *Prober, th Thresholds, now time.Time) Report

Build compares the snapshots, optionally probes every source domain on both sides, and returns the finished report. A nil prober skips the probes.

func (*Report) Finish

func (r *Report) Finish()

Finish sorts the differences (blocking first), fills the counts and the verdict.

func (Report) HasBlocking

func (r Report) HasBlocking() bool

HasBlocking reports whether cutover should be held.

type Severity

type Severity string

Severity ranks a difference. Only Blocking fails the verdict.

const (
	Blocking Severity = "blocking"
	Warning  Severity = "warning"
	Info     Severity = "info"
)

Difference severities.

type Source

type Source struct {
	Platform string
	Apps     []SourceApp
	DBs      []DB
}

Source is the key-only view of a source platform.

func SnapshotSource

func SnapshotSource(d *platformimport.Discovery) Source

SnapshotSource drops everything but names from a discovery. Env values are not copied, so nothing downstream can leak one.

type SourceApp

type SourceApp struct {
	ID            string
	Name          string
	Domains       []string
	EnvKeys       []string
	BuildTimeKeys []string
	Volumes       []string
	Jobs          []Job
}

SourceApp is one source app reduced to what parity compares. EnvKeys holds names only.

type Target

type Target struct {
	Apps []TargetApp
	DBs  []DB
}

Target is the key-only view of this instance.

type TargetApp

type TargetApp struct {
	Name string
	// SourceKey is the import label ("platform:id"), empty for an app made by hand.
	SourceKey string
	// Staged marks an imported app that holds its domains back until cutover.
	Staged  bool
	Domains []string
	EnvKeys []string
	Volumes []string
	Jobs    []Job
}

TargetApp is one app on this instance, reduced the same way.

type Thresholds

type Thresholds struct {
	TLSWarnDays    int
	LatencyFactor  float64
	LatencyFloorMS int64
}

Thresholds classify probe results. All come from env, with the defaults above.

func ThresholdsFromEnv

func ThresholdsFromEnv(lookup func(string) (string, bool)) Thresholds

ThresholdsFromEnv reads the thresholds through lookup.

type Totals

type Totals struct {
	Category Category `json:"category"`
	Source   int      `json:"source"`
	Target   int      `json:"target"`
	Matched  int      `json:"matched"`
	Blocking int      `json:"blocking"`
	Warning  int      `json:"warning"`
	Info     int      `json:"info"`
}

Totals counts one category on each side.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL