validation

package
v0.5.7 Latest Latest
Warning

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

Go to latest
Published: Jul 30, 2026 License: Apache-2.0 Imports: 9 Imported by: 0

README

pkg/core/validation

Checks whether a target migration model (cloudmodel.RecommendedInfra) is internally consistent and can be provisioned, without creating or modifying any CSP/Tumblebug resource. Backs both the standalone POST /validation/ns/{nsId}/infra API and the pre-flight gate that pkg/core/migration runs immediately before provisioning, so the two never drift apart.

Entry point

result := validation.ValidateTargetInfra(nsId, targetInfraModel, useExisting)
// result.Valid  bool
// result.Issues []ValidationIssue{Code, Severity, Path, Message}
err := result.Err() // non-nil summary error, or nil if Valid

What it checks

  • Naming & referential integrity (common.ValidateComposedNames): name format, and internal references resolve within the submitted model.
  • Required fields, which differ by useExisting: node group vNetId/sshKeyId/securityGroupIds (true) vs. targetVNet.name / targetSshKey.name / security group name (false).
  • Resource name collision / availability against Tumblebug: must NOT already exist (useExisting=false), or must exist under the same CSP/region connection the node group requests — not just under the same ID (useExisting=true, CONNECTION_MISMATCH otherwise).
  • VM spec/image compatibility per node group (Tumblebug spec/image lookup + pkg/compat).
  • Infra (MCI) name collision: targetInfra.name must not already exist.

Running the tests

go test ./pkg/core/validation/... -v -cover

Plain go test ./pkg/core/validation/... (no -v) prints a single ok ... line — the quietest form to paste into a PR or chat.

No live Tumblebug, Spider, or CSP credentials are needed. infra_test.go's TestMain starts an httptest.Server that serves canned JSON for the handful of Tumblebug endpoints this package reads (VNet/SshKey/SecurityGroup/ Infra/Spec/Image), then points tbclient at it via tbclient.Init(...). Any request path not in the fixtures map 404s automatically, which is exactly the "resource does not exist" case most scenarios need — so only the "found" fixtures require an explicit map entry.

tbclient.NewSession() uses a single process-global client guarded by sync.Once, so tbclient.Init can only meaningfully run once per test binary. All scenarios therefore share one fake server; baseTarget() builds a fresh, fully-valid model per test, and small targetOption helpers (withVNetName, withSshKeyName, withSecurityGroupName) repoint it at a specific fixture (or a nonexistent name) while keeping referential integrity intact.

Adding a new scenario
  1. If it needs a resource to already exist, add a fixture to the fixtures map in infra_test.go (path → status/body). Not-found cases need nothing.
  2. Add a case to the tests table in TestValidateTargetInfra: useExisting, the targetOptions to reach that state, and the expected wantValid/ wantCode.
  3. Give fixture names that read as intent (vnet-mismatch, vnet-does-not-exist) — the fixtures map doubles as documentation of what each stands in for.

Documentation

Overview

Package validation checks whether a target migration model is consistent and can be provisioned, without creating or modifying any CSP/Tumblebug resource. The same checks back both the standalone validation API and the pre-flight gate that migration execution runs immediately before creating resources.

Index

Constants

View Source
const (
	CodeRequiredFieldMissing    = "REQUIRED_FIELD_MISSING"
	CodeReferentialIntegrity    = "REFERENTIAL_INTEGRITY"
	CodeResourceAlreadyExists   = "RESOURCE_ALREADY_EXISTS"
	CodeResourceNotAvailable    = "RESOURCE_NOT_AVAILABLE"
	CodeSpecImageIncompatible   = "SPEC_IMAGE_INCOMPATIBLE"
	CodeInvalidConnectionName   = "INVALID_CONNECTION_NAME"
	CodeSpecOrImageLookupFailed = "SPEC_OR_IMAGE_LOOKUP_FAILED"
	CodeConnectionMismatch      = "CONNECTION_MISMATCH"
)

Issue codes, stable identifiers a UI can switch on without parsing Message.

Variables

This section is empty.

Functions

This section is empty.

Types

type NetworkRequirement

type NetworkRequirement struct {
	VNetId         string
	SubnetIds      []string
	ConnectionName string
}

NetworkRequirement represents the virtual network and subnets required by NodeGroups.

func DeriveNetworkRequirements

func DeriveNetworkRequirements(nodeGroups []cloudmodel.CreateNodeGroupReq) []NetworkRequirement

DeriveNetworkRequirements groups and extracts virtual network requirements from NodeGroups.

type SecurityGroupRequirement

type SecurityGroupRequirement struct {
	SecurityGroupId string
	VNetId          string
	ConnectionName  string
}

SecurityGroupRequirement represents the security group required by NodeGroups.

func DeriveSecurityGroupRequirements

func DeriveSecurityGroupRequirements(nodeGroups []cloudmodel.CreateNodeGroupReq) []SecurityGroupRequirement

DeriveSecurityGroupRequirements extracts unique security group requirements from NodeGroups.

type Severity

type Severity string

Severity classifies how serious a ValidationIssue is.

const (
	// SeverityError means the target model cannot be migrated as-is.
	SeverityError Severity = "error"

	// SeverityWarning flags something worth the caller's attention that
	// does not by itself block migration.
	SeverityWarning Severity = "warning"
)

type SshKeyRequirement

type SshKeyRequirement struct {
	SshKeyId       string
	ConnectionName string
}

SshKeyRequirement represents the SSH key required by NodeGroups.

func DeriveSshKeyRequirements

func DeriveSshKeyRequirements(nodeGroups []cloudmodel.CreateNodeGroupReq) []SshKeyRequirement

DeriveSshKeyRequirements extracts unique SSH key requirements from NodeGroups.

type ValidationIssue

type ValidationIssue struct {
	Code     string   `json:"code"`     // stable machine-readable identifier, one of the Code* constants
	Severity Severity `json:"severity"` // error | warning
	Path     string   `json:"path"`     // location of the offending field, e.g. "targetInfra.nodeGroups[0].imageId"
	Message  string   `json:"message"`  // human-readable detail
}

ValidationIssue is a single problem found while validating a target model.

func CheckNetworkAvailability

func CheckNetworkAvailability(nsId string, netRequirement NetworkRequirement, vNetCreationReq cloudmodel.VNetReq) (needsCreate bool, issue *ValidationIssue)

CheckNetworkAvailability reports whether the required vNet and subnets already exist, or - if not - whether vNetCreationReq carries enough data to create them. It performs reads only; no resource is created or modified.

func CheckSecurityGroupAvailability

func CheckSecurityGroupAvailability(nsId string, sgRequirement SecurityGroupRequirement, sgCreationReqList []cloudmodel.SecurityGroupReq) (needsCreate bool, issue *ValidationIssue)

CheckSecurityGroupAvailability reports whether the required security group already exists, or - if not - whether sgCreationReqList carries enough data (a matching entry with ConnectionName and VNetId resolvable) to create it. It performs reads only; no resource is created or modified.

func CheckSshKeyAvailability

func CheckSshKeyAvailability(nsId string, sshKeyRequirement SshKeyRequirement, sshKeyCreationReq cloudmodel.SshKeyReq) (needsCreate bool, issue *ValidationIssue)

CheckSshKeyAvailability reports whether the required SSH key already exists, or - if not - whether sshKeyCreationReq carries enough data to create it. It performs reads only; no resource is created or modified.

type ValidationResult

type ValidationResult struct {
	Valid  bool              `json:"valid"`
	Issues []ValidationIssue `json:"issues"`
}

ValidationResult is the outcome of validating a target model.

func ValidateTargetInfra

func ValidateTargetInfra(nsId string, targetInfraModel *cloudmodel.RecommendedInfra, useExisting bool) ValidationResult

ValidateTargetInfra checks whether targetInfraModel is internally consistent and can be migrated into namespace nsId, given how resources are provisioned under useExisting:

  • useExisting=false: CreateInfra creates fresh VNet/SshKey/SecurityGroups, so none of them may already exist.
  • useExisting=true: CreateInfraWithExisting reuses a resource by ID if found, otherwise falls back to creating it from the accompanying Target*Req data, so a missing resource is only an error when that fallback data is absent.

In both modes the check performs Tumblebug reads only - no resource is created, modified, or deleted. Because state can change between this call and an actual migration, a "valid" result is a best-effort snapshot, not a guarantee; the migration path re-runs this same validation immediately before provisioning.

All applicable checks run to completion and their issues are accumulated, rather than stopping at the first failure, so a caller (e.g. a Portal UI) can surface every problem found in a single call.

func (ValidationResult) Err

func (r ValidationResult) Err() error

Err joins every SeverityError issue's message into a single error, or returns nil when the result is Valid. It mirrors context.Context.Err() / bufio.Scanner.Err(): nil means "nothing went wrong."

Jump to

Keyboard shortcuts

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