Documentation
¶
Index ¶
- Constants
- 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 AuthMapping
- type ClusterLinking
- type CostReconciliationCfg
- type EnterpriseCaps
- type PlanConfig
- type PlanInputDefaults
- type PlanService
- type SchemaLinking
- type Thresholds
Constants ¶
const ( TargetAuthAPIKeys = "confluent_cloud_api_keys" TargetAuthMTLS = "mtls" TargetAuthOAuth = "oauth" )
Target auth method tokens. Customer-facing values written into `plan-inputs.yaml` and rendered back in the AuthDecision JSON.
const ( SourceAuthSCRAM = "scram" SourceAuthIAM = "iam" SourceAuthMTLS = "mtls" SourceAuthUnauth = "unauth" )
Source-auth tokens. Stable strings — these appear in the rendered Plan (AuthDecision.SourceAuths) and key the auth_mapping table in plan-config.yaml. Don't rename without bumping a schema doc.
const ( DiscoveredClientAuthIAM = "IAM" DiscoveredClientAuthSASLSCRAM = "SASL_SCRAM" DiscoveredClientAuthTLS = "TLS" DiscoveredClientAuthUnauthenticated = "UNAUTHENTICATED" DiscoveredClientAuthUnknown = "UNKNOWN" )
DiscoveredClientAuth* mirrors the literal strings that `kcp scan client-inventory` writes into `DiscoveredClient.Auth` (see `cmd/scan/client_inventory/kafka_trace_line_parser.go`).
**Heads-up:** `types.AuthTypeIAM` in `internal/types/types.go` resolves to `"SASL/IAM"` — a DIFFERENT string used elsewhere. Use these constants when comparing against the persisted client inventory, not the `types.AuthType*` constants.
const ( DowntimeZero = "zero" DowntimeSecondsPerService = "seconds_per_service" DowntimeMinutesPerService = "minutes_per_service" DowntimeScheduledWindowSequential = "scheduled_window_sequential" DowntimeScheduledWindowAllAtOnce = "scheduled_window_all_at_once" DowntimeLetConfluentChoose = "let_confluent_choose" DowntimeUnsetFallback = DowntimeLetConfluentChoose )
downtime_tolerance enum values. Stable identifiers — used as YAML input tokens AND as keys in the style mapping.
const ( PrereqNotStarted = "not_started" PrereqStatusInProgressInput = "in_progress" PrereqStatusCompleteInput = "complete" )
Gateway prereq status enum values.
const ( EffortSignalIDIAMClientCount = "iam_to_scram_client_count" EffortSignalIDMM2CheckpointTopics = "mm2_checkpoint_topic_count" EffortSignalIDSelfManagedConnectFleets = "self_managed_connect_fleet_count" EffortSignalIDGlueSerializerMigration = "glue_serializer_migration_count" )
Stable Effort Signal IDs. Matches the spec row order.
const ( RedFlagIDSchemalessSource = "schemaless_source" RedFlagIDKafkaVersionBelowCLFloor = "kafka_version_below_cl_floor" RedFlagIDIAMAuthEnabled = "iam_auth_enabled" RedFlagIDGlueSRInUse = "glue_sr_in_use" RedFlagIDPartitionApproachingCap = "partition_approaching_cap" RedFlagIDMSKConnectPresent = "msk_connect_present" RedFlagIDSelfManagedConnectPresent = "self_managed_connect_present" RedFlagIDMultiRegionSource = "multi_region_source" RedFlagIDZeroACLsWithIAM = "zero_acls_with_iam" RedFlagIDClientInventoryGap = "client_inventory_gap" RedFlagIDMSKExpressBrokerTier = "msk_express_broker_tier" RedFlagIDTieredStorageInUse = "tiered_storage_in_use" RedFlagIDEOSInUse = "eos_in_use" RedFlagIDKafkaStreamsInUse = "kafka_streams_in_use" RedFlagIDBroadTopicPatternMatch = "broad_topic_pattern_match" )
Stable Red Flag IDs. Matches the spec's row numbering — kept stable so JSON consumers can branch on the ID without parsing the title.
const ( SchemaStrategyUnknown = "unknown" SchemaStrategyNoSchemas = "no_schemas" SchemaStrategyAdoptSchemasDuringMigration = "adopt_schemas_during_migration" SchemaStrategyMigrateExistingSchemaRegistry = "migrate_existing_schema_registry" SchemaCPEditionEnterprise = "enterprise" SchemaCPEditionCommunity = "community" )
Plan-input enum tokens for schema migration. Stable customer-facing strings — surfaced in plan-inputs.yaml and the rendered Plan.
const ( ConsumerHistoryRequired = "required" ConsumerHistoryNotRequired = "not_required" ConsumerHistoryUnknown = "unknown" HistoricalKeepMSKRunning = "keep_msk_running_until_data_expires" HistoricalBulkLoadExtern = "bulk_load_historical_via_external_tool" HistoricalDeferToAccount = "defer_to_account_team" )
Plan-input enum tokens for tiered-storage knobs. Stable customer-facing strings; the resolver surfaces them through PlanInputsResolved.ConsumerHistoryRequirement and HistoricalDataStrategy.
Variables ¶
This section is empty.
Functions ¶
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 AuthMapping ¶ added in v0.8.4
type AuthMapping struct {
Target string `yaml:"target"`
GatewayCompatible bool `yaml:"gateway_compatible"`
TransparentSwap bool `yaml:"transparent_swap"`
Note string `yaml:"note"`
Source string `yaml:"source"`
LastVerified string `yaml:"last_verified"`
}
AuthMapping is one row in the source→target auth lookup table keyed by source-auth token (scram / iam / mtls / unauth). Defaults resolve via this table when the customer doesn't override via `target_auth_method`. Source + LastVerified carry the row's provenance (which Confluent doc the values come from, and when an engineer last checked it).
type ClusterLinking ¶
type CostReconciliationCfg ¶ added in v0.8.4
type CostReconciliationCfg struct {
UsageFamilies []string `yaml:"usage_families"`
}
CostReconciliationCfg pins the AWS Cost Explorer usage-string families that count as MSK broker spend. Today AWS bills MSK under `Kafka.*` and `Express.*`; new broker tiers will land as new family tokens. Admins extend this list when a new tier ships without waiting for a kcp release.
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"`
SchemaLinking SchemaLinking `yaml:"schema_linking"`
PlanInputDefaults PlanInputDefaults `yaml:"plan_input_defaults"`
AuthMapping map[string]AuthMapping `yaml:"auth_mapping"`
Thresholds Thresholds `yaml:"thresholds"`
CostReconciliation CostReconciliationCfg `yaml:"cost_reconciliation"`
}
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"`
// Cutover defaults.
DowntimeTolerance string `yaml:"downtime_tolerance"`
SubPattern string `yaml:"sub_pattern"`
PreferGateway bool `yaml:"prefer_gateway"`
ConfluentForKubernetesStatus string `yaml:"confluent_for_kubernetes_status"`
CCGatewayLicenseStatus string `yaml:"cc_gateway_license_status"`
IAMPreMigrationStatus string `yaml:"iam_pre_migration_status"`
// Auth defaults.
TargetAuthMethod string `yaml:"target_auth_method"`
// Schema-migration defaults. Defaults below resolve to
// `unknown` so first-run plans always ask the customer to declare
// strategy + reachability + CP version/edition rather than silently
// picking a path.
SchemaStrategy string `yaml:"schema_strategy"`
ConfluentSRCPVersion string `yaml:"confluent_sr_cp_version,omitempty"`
ConfluentSRCPEdition string `yaml:"confluent_sr_cp_edition,omitempty"`
}
type PlanService ¶
type PlanService struct {
// contains filtered or unexported fields
}
Function-naming convention across this package:
`decide*` — produces a verdict / path from inputs. One decision per cluster (sizing, cluster type, networking, auth) or one per fleet (cutover, schema). Output is the rendered §section's primary recommendation.
`detect*` — enumerates findings or signals from `state` / `plan` (red flags, effort signals, tiered storage, cost reconciliation, all OQ detectors). Output is a list/section, not a single verdict. Some detectors also apply small input cascades (e.g. `detectTieredStorage` defaults `HistoricalDataStrategy`) — that's deliberate: the cascade is scoped to the section's findings, not a standalone decision.
`compute*` — pure numeric / structural transforms with no verdict (e.g. `computeClusterSizing`, `computeCutoverOverrides`). Output is intermediate data the renderer + decide* consume.
PlanService orchestrates the deterministic plan-generation pipeline. Each Build step is a pure function so the test surface is the orchestration, not its parts.
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.
type SchemaLinking ¶ added in v0.8.4
type SchemaLinking struct {
MinCPVersion string `yaml:"min_cp_version"`
RequiresCPEdition string `yaml:"requires_cp_edition"`
Source string `yaml:"source"`
LastVerified string `yaml:"last_verified"`
}
SchemaLinking pins the version + edition floor that source Confluent SR must clear for the Schema Linking path. Customers below these floors get the `defer_to_account_team` verdict (REST API export / import is technically possible but kcp doesn't drive it). The values come from the [Schema Linking on CP docs](https://docs.confluent.io/platform/current/schema-registry/schema-linking-cp.html); last-verified date below tracks when an engineer cross-checked them.
type Thresholds ¶ added in v0.8.4
type Thresholds struct {
// StaleStateDays — emit the state-file-stale OQ when the state
// snapshot is older than this many days.
StaleStateDays int `yaml:"stale_state_days"`
// PNIGatewayBreakeven — projected PNI gateway count at or above
// which the recommendation flips from PNI to PrivateLink.
PNIGatewayBreakeven int `yaml:"pni_gateway_breakeven"`
// PartitionApproachingFraction — Red Flag row 5 fires when
// user-topic partitions exceed this fraction of the cluster's
// sized eCKU capacity (per_eCKU_partition_rate * FinalECKU).
// 0.30 means "fire at 30% of sized capacity"; pre-fix this was
// hardcoded in red_flags.go.
PartitionApproachingFraction float64 `yaml:"partition_approaching_fraction"`
}
Thresholds collects numeric cutoffs that the rule engine and the renderer need but that aren't customer-facing knobs — pulled out so an admin can tune them without code edits if a tenant has a genuinely different operating envelope.