plan

package
v0.8.3 Latest Latest
Warning

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

Go to latest
Published: Jun 11, 2026 License: Apache-2.0 Imports: 15 Imported by: 0

Documentation

Index

Constants

View Source
const ExpectedSchemaVersion = 1

ExpectedSchemaVersion is the schema_version this loader understands. Bump in lockstep with breaking YAML structure changes.

Variables

This section is empty.

Functions

func ComputeClusterSizing

func ComputeClusterSizing(c types.ProcessedCluster, cfg *PlanConfig, inputs types.PlanInputsResolved) types.ClusterSizing

ComputeClusterSizing implements the deterministic sizing formula:

max_ratio = max(P95In/per_eCKU_ingress_mbps,
                P95Out/per_eCKU_egress_mbps,
                user_partitions/per_eCKU_partition_rate)
sized_eCKU = CEIL(max_ratio * (1 + headroom))
final_eCKU = max(sized_eCKU, SLA_floor)

Peak burst eCKU is derived from instantaneous max metric values and used downstream to decide PrivateLink vs PNI.

When throughput metrics are missing (e.g. `kcp discover` ran without `kcp scan metrics`), the function returns a degraded ClusterSizing with FinalECKU = SLA floor and Degraded = true rather than failing the whole plan build. The renderer surfaces the gap so the customer knows the sizing column is a placeholder.

func DecideClusterType

DecideClusterType returns the recommended Confluent Cloud cluster type for one source cluster.

Standard is intentionally not a verdict: MSK migration workloads benefit from Enterprise's elastic scaling and PrivateLink/PNI options that Standard doesn't offer. Enterprise is the default; hard-limit rules escalate to Dedicated when a cap is exceeded or a workload constraint can't be served on Enterprise.

func DecideNetworking

DecideNetworking picks the Confluent Cloud networking product for one cluster.

Dedicated + target_cloud != "aws"                        → PrivateLink (PNI / TGW / VPC Peering are AWS-only)
Dedicated + existing_vpc_connectivity == transit_gateway → Transit Gateway
Dedicated + existing_vpc_connectivity == vpc_peering     → VPC Peering
Dedicated (otherwise)                                    → PNI
Enterprise + target_cloud != "aws"                       → PrivateLink (PNI is AWS-to-AWS only)
Enterprise + cc_egress_required                          → PrivateLink (PNI lacks native CC→customer egress)
Enterprise + projected_pni_gateway_count ≥ 2             → PrivateLink
Enterprise (otherwise)                                   → PNI (default — scales to 32 eCKU vs PrivateLink's 10)

`existing_vpc_connectivity` is only honored on the AWS-Dedicated path — Transit Gateway and VPC Peering are Dedicated-only AWS products.

func LoadPlanInputs

func LoadPlanInputs(path string) (*types.PlanInputs, error)

LoadPlanInputs reads plan-inputs.yaml. Returns nil *PlanInputs if path is empty (no file supplied is a valid state — the Plan still generates from defaults). Missing fields never fail because no field is required at the YAML schema level.

func RenderJSON

func RenderJSON(p *types.Plan) ([]byte, error)

RenderJSON serialises a Plan to canonical 2-space-indented JSON. Stable key ordering comes for free from struct field order — any map members are encoded by Go's stdlib in sorted key order since Go 1.12.

func RenderMarkdown

func RenderMarkdown(p *types.Plan, cfg *PlanConfig) ([]byte, error)

RenderMarkdown emits the human-readable Plan: Source Environment, Sizing & Cluster Decisions, Actions Needed, and collapsed appendices. `cfg` must be the same PlanConfig the PlanService used to build the plan (product-fact numbers in the Definitions block and the partition cap in the appendix read from it).

func ResolvePlanInputs

func ResolvePlanInputs(in *types.PlanInputs, cfg *PlanConfig) types.PlanInputsResolved

ResolvePlanInputs merges customer-supplied PlanInputs with pinned defaults from PlanConfig. Customer-set fields win; everything else falls back to PlanConfig.PlanInputDefaults. Raw is preserved so downstream consumers can detect which sizing fields the customer explicitly set (HeadroomFraction, SLATarget, SizingPercentile, etc.).

func ResolvePlanInputsForCluster

func ResolvePlanInputsForCluster(in *types.PlanInputs, cfg *PlanConfig, clusterName string) types.PlanInputsResolved

ResolvePlanInputsForCluster layers a cluster-specific override on top of the resolved globals. If `in.Clusters[clusterName]` is set, every non-nil field in it wins over the global. Otherwise the global view is returned unchanged. Caller uses this per-cluster during Plan build so heterogeneous fleets get the right verdicts without one global flag flipping every cluster's tier.

**Hot path note:** when iterating many clusters, prefer `applyClusterOverride` against a pre-resolved global view — this function re-resolves globals on every call.

Types

type ClusterLinking

type ClusterLinking struct {
	SourceMinKafkaVersion string `yaml:"source_min_kafka_version"`
	ExpressTierSupported  string `yaml:"express_tier_supported"`
	Source                string `yaml:"source"`
}

type EnterpriseCaps

type EnterpriseCaps struct {
	PerECKUIngressMBps   int    `yaml:"per_eCKU_ingress_mbps"`
	PerECKUEgressMBps    int    `yaml:"per_eCKU_egress_mbps"`
	PerECKUPartitionRate int    `yaml:"per_eCKU_partition_rate"`
	PrivateLinkMaxECKU   int    `yaml:"privatelink_max_eCKU"`
	PNIMaxECKU           int    `yaml:"pni_max_eCKU"`
	ACLCountCap          int    `yaml:"acl_count_cap"`
	Source               string `yaml:"source"`
}

type PlanConfig

type PlanConfig struct {
	SchemaVersion            int    `yaml:"schema_version"`
	LastVerified             string `yaml:"last_verified"`
	KCPVersionAtVerification string `yaml:"kcp_version_at_verification"`

	EnterpriseCaps    EnterpriseCaps    `yaml:"enterprise_caps"`
	ClusterLinking    ClusterLinking    `yaml:"cluster_linking"`
	PlanInputDefaults PlanInputDefaults `yaml:"plan_input_defaults"`
}

PlanConfig is the deserialized plan-config.yaml. The embedded copy is the default; an admin-supplied override file replaces only the fields it specifies (standard yaml unmarshal semantics — slices replace whole, maps merge by key).

func LoadPlanConfig

func LoadPlanConfig(overridePath string) (*PlanConfig, error)

LoadPlanConfig returns the embedded plan-config.yaml, optionally overridden by the file at overridePath. Pass an empty string to skip the override.

func (*PlanConfig) Validate

func (c *PlanConfig) Validate() error

type PlanInputDefaults

type PlanInputDefaults struct {
	SizingPercentile   string         `yaml:"sizing_percentile"`
	HeadroomFraction   float64        `yaml:"headroom_fraction"`
	SpikyWorkloadRatio float64        `yaml:"spiky_workload_ratio"`
	SLAFloorECKU       map[string]int `yaml:"sla_floor_eCKU"`

	// Customer-declared hard requirements (all default false).
	EnforceSchemasAtTheBroker            bool `yaml:"enforce_schemas_at_the_broker"`
	RequiresHighThroughputRESTProduceAPI bool `yaml:"requires_high_throughput_rest_produce_api"`
	Requires9995SLAWithinSingleZone      bool `yaml:"requires_99_95_sla_within_a_single_zone"`

	// Target cloud + existing VPC connectivity (Dedicated-path networking).
	TargetCloud             string `yaml:"target_cloud"`
	ExistingVPCConnectivity string `yaml:"existing_vpc_connectivity"`

	// Networking triggers (PNI→PrivateLink) — see PlanInputsResolved.
	CCEgressRequired         bool `yaml:"cc_egress_required"`
	ProjectedPNIGatewayCount int  `yaml:"projected_pni_gateway_count"`
}

type PlanService

type PlanService struct {
	// contains filtered or unexported fields
}

PlanService orchestrates the deterministic plan-generation pipeline. MVP scope: source-environment summary, sizing, cluster-type, networking. Auth approach, switchover, red flags, etc. land in follow-up PRs.

func NewPlanService

func NewPlanService(cfg *PlanConfig, now func() time.Time) *PlanService

NewPlanService wires a PlanConfig into a PlanService. now is overridable for deterministic tests; pass nil for time.Now.

func (*PlanService) Build

func (s *PlanService) Build(state types.ProcessedState, inputs types.PlanInputsResolved, stateFilePath string) (*types.Plan, error)

Build produces a Plan from a ProcessedState and resolved plan-inputs. Each step is a pure function so the test surface is the orchestration, not its parts.

Jump to

Keyboard shortcuts

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