Documentation
¶
Index ¶
- Constants
- func ComputeClusterSizing(c types.ProcessedCluster, cfg *PlanConfig, inputs types.PlanInputsResolved) types.ClusterSizing
- func DecideClusterType(c types.ProcessedCluster, sizing types.ClusterSizing, cfg *PlanConfig, ...) types.ClusterTypeDecision
- func DecideNetworking(sizing types.ClusterSizing, ct types.ClusterTypeDecision, cfg *PlanConfig, ...) types.NetworkingDecision
- func LoadPlanInputs(path string) (*types.PlanInputs, error)
- func RenderJSON(p *types.Plan) ([]byte, error)
- func RenderMarkdown(p *types.Plan, cfg *PlanConfig) ([]byte, error)
- func ResolvePlanInputs(in *types.PlanInputs, cfg *PlanConfig) types.PlanInputsResolved
- func ResolvePlanInputsForCluster(in *types.PlanInputs, cfg *PlanConfig, clusterName string) types.PlanInputsResolved
- type ClusterLinking
- type EnterpriseCaps
- type PlanConfig
- type PlanInputDefaults
- type PlanService
Constants ¶
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 ¶
func DecideClusterType(c types.ProcessedCluster, sizing types.ClusterSizing, cfg *PlanConfig, inputs types.PlanInputsResolved) types.ClusterTypeDecision
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 ¶
func DecideNetworking(sizing types.ClusterSizing, ct types.ClusterTypeDecision, cfg *PlanConfig, inputs types.PlanInputsResolved) types.NetworkingDecision
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 ¶
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 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.