Packages:
Resource Types:
GroundStationLifecycle manages the lifecycle of a satellite ground station, including health monitoring, firmware OTA, and GitOps-based configuration.
| Name | Type | Description | Required |
|---|---|---|---|
| apiVersion | string | ntn.operators.dev/v1alpha1 | true |
| kind | string | GroundStationLifecycle | true |
| metadata | object | Refer to the Kubernetes API documentation for the fields of the `metadata` field. | true |
| spec | object |
GroundStationLifecycleSpec defines the desired state of a ground station. |
true |
| status | object |
GroundStationLifecycleStatus defines the observed state of a ground station. |
false |
GroundStationLifecycleSpec defines the desired state of a ground station.
| Name | Type | Description | Required |
|---|---|---|---|
| deployment | object |
deployment defines the station deployment and location. |
true |
| hardware | object |
hardware describes the ground station equipment. |
true |
| firmware | object |
firmware defines OTA update configuration. |
false |
| monitoring | object |
monitoring defines health check parameters. |
false |
deployment defines the station deployment and location.
| Name | Type | Description | Required |
|---|---|---|---|
| location | object |
location is the geographic position of the ground station. Validations: |
true |
| gitopsRepo | string |
gitopsRepo is the Git repository URL for GitOps-managed configuration. |
false |
| k8sDistro | enum |
k8sDistro is the Kubernetes distribution running on the edge box. Enum: k3s, microk8s, rke2 Default: k3s |
false |
location is the geographic position of the ground station.
| Name | Type | Description | Required |
|---|---|---|---|
| lat | string |
lat is the latitude in decimal degrees (string, e.g., "25.0330"). |
true |
| lon | string |
lon is the longitude in decimal degrees (string, e.g., "121.5654"). |
true |
| alt | string |
alt is the altitude in meters above sea level (string, e.g., "15"). |
false |
hardware describes the ground station equipment.
| Name | Type | Description | Required |
|---|---|---|---|
| model | string |
model is the hardware model identifier. |
true |
| vendor | string |
vendor is the hardware manufacturer (e.g., "ennoconn"). |
true |
| antennaType | string |
antennaType is the antenna type (e.g., "flat-panel", "parabolic"). |
false |
| bands | []string |
bands lists the supported frequency bands (e.g., ["Ka", "Ku", "S"]). |
false |
firmware defines OTA update configuration.
| Name | Type | Description | Required |
|---|---|---|---|
| autoUpdate | boolean |
autoUpdate enables automatic firmware updates. Default: false |
false |
| channel | string |
channel is the firmware update channel (e.g., "stable", "beta"). Default: stable |
false |
| maintenanceWindow | string |
maintenanceWindow is the time window for updates.
Format: "HH:MM-HH:MM UTC" (e.g., "02:00-04:00 UTC"). |
false |
monitoring defines health check parameters.
| Name | Type | Description | Required |
|---|---|---|---|
| endpoint | string |
endpoint is the monitoring endpoint of the ground station agent. |
false |
| healthCheckInterval | string |
healthCheckInterval is how often to check ground station health. Default: 30s |
false |
GroundStationLifecycleStatus defines the observed state of a ground station.
| Name | Type | Description | Required |
|---|---|---|---|
| conditions | []object |
conditions represent the current state of the ground station. |
false |
| firmwareUpdateStarted | string |
firmwareUpdateStarted is when the current firmware update began.
Used for timeout detection. Format: date-time |
false |
| firmwareVersion | string |
firmwareVersion is the currently running firmware version. |
false |
| k8sVersion | string |
k8sVersion is the Kubernetes version running on the edge node. |
false |
| lastHealthCheck | string |
lastHealthCheck is the timestamp of the last successful health check. Format: date-time |
false |
| phase | enum |
phase is the current lifecycle phase. Enum: Provisioning, Running, Degraded, Offline, Updating |
false |
Condition contains details for one aspect of the current state of this API Resource.
| Name | Type | Description | Required |
|---|---|---|---|
| lastTransitionTime | string |
lastTransitionTime is the last time the condition transitioned from one status to another.
This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. Format: date-time |
true |
| message | string |
message is a human readable message indicating details about the transition.
This may be an empty string. |
true |
| reason | string |
reason contains a programmatic identifier indicating the reason for the condition's last transition.
Producers of specific condition types may define expected values and meanings for this field,
and whether the values are considered a guaranteed API.
The value should be a CamelCase string.
This field may not be empty. |
true |
| status | enum |
status of the condition, one of True, False, Unknown. Enum: True, False, Unknown |
true |
| type | string |
type of condition in CamelCase or in foo.example.com/CamelCase. |
true |
| observedGeneration | integer |
observedGeneration represents the .metadata.generation that the condition was set based upon.
For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
with respect to the current state of the instance. Format: int64 Minimum: 0 |
false |
NTNCellConfig manages NTN-specific radio parameters for a gNB cell, delegating configuration to the specified NTN backend provider.
| Name | Type | Description | Required |
|---|---|---|---|
| apiVersion | string | ntn.operators.dev/v1alpha1 | true |
| kind | string | NTNCellConfig | true |
| metadata | object | Refer to the Kubernetes API documentation for the fields of the `metadata` field. | true |
| spec | object |
NTNCellConfigSpec defines the desired NTN cell configuration. Validations: |
true |
| status | object |
NTNCellConfigStatus defines the observed state of NTNCellConfig. |
false |
NTNCellConfigSpec defines the desired NTN cell configuration.
| Name | Type | Description | Required |
|---|---|---|---|
| ntn | object |
ntn contains NTN-specific radio parameters per 3GPP TS 38.213 / OCUDU geo_ntn.yml. Validations: |
true |
| provider | object |
provider specifies which NTN backend to configure. |
true |
| cellID | object |
cellID identifies the OCUDU cell (plmn + nci) that runtime remote commands
target. Required when provider.remoteControl is set; the value must match
the cell the gNB booted with. Unset ⇒ ConfigMap bootstrap path only. |
false |
| cellOverrides | object |
cellOverrides allows fine-tuning PUCCH, PDSCH, PRACH, and RRC parameters. |
false |
| ephemerisNoradID | integer |
ephemerisNoradID selects which satellite's propagated state vector, from the
referenced SatelliteEphemeris (ephemerisRef), to push at runtime (#176). When
unset, the single tracked satellite's state is used; if the referenced ephemeris
exposes more than one satellite the push fails closed (EphemerisPushed=False,
reason EphemerisSelectionAmbiguous) until this field selects one — the controller
never guesses which satellite to serve. |
false |
| ephemerisRef | string |
ephemerisRef is the name of a SatelliteEphemeris CR in the same namespace.
When set, the controller re-reconciles this NTNCellConfig whenever the
referenced SatelliteEphemeris is updated and invokes runtime ephemeris push
on the provider reconcile path. The static ephemeris in spec.ntn
(ephemerisECEF or ephemerisOrbital) remains required as the source payload. |
false |
ntn contains NTN-specific radio parameters per 3GPP TS 38.213 / OCUDU geo_ntn.yml.
| Name | Type | Description | Required |
|---|---|---|---|
| cellSpecificKoffset | integer |
cellSpecificKoffset is the cell-specific K_offset for NTN scheduling timing
(3GPP TS 38.213 / TS 38.300 §16.14.2). Its unit is milliseconds: OCUDU stores
cell_specific_koffset as std::chrono::milliseconds and converts it to
operating-SCS slots internally, so the value passes through this operator
unchanged with no unit conversion. (3GPP expresses K_offset as a slot count
assuming the 15 kHz reference SCS, where 1 slot = 1 ms; that identity is only
how the IE is defined, not a conversion the user applies here.)
The 3GPP IE cellSpecificKoffset-r17 is INTEGER(0..1023), but OCUDU rejects 0
(its CLI and config validation enforce 1-1023), so Minimum is 1 to mirror the
backend rather than the spec. Default: 150 Minimum: 1 Maximum: 1023 |
false |
| distanceThreshold | integer |
distanceThreshold sets the distance threshold for cell
selection in metres. Minimum: 0 |
false |
| ephemerisECEF | object |
ephemerisECEF defines the satellite position and velocity in ECEF coordinates.
Mutually exclusive with ephemerisOrbital. |
false |
| ephemerisOrbital | object |
ephemerisOrbital defines the satellite orbit using Keplerian elements.
Mutually exclusive with ephemerisECEF. Preferred for LEO satellites
where source data is in OMM/TLE form (CelesTrak, SpaceTrack). |
false |
| epochTime | object |
epochTime defines the SFN/subframe reference for NTN timing alignment. |
false |
| feederLinkInfo | object |
feederLinkInfo provides feeder link parameters for Doppler compensation. |
false |
| movingRefLocation | object |
movingRefLocation defines the Earth-moving reference location for LEO NTN cells.
3GPP Release 18 SIB19 field. Used by UEs for timing/Doppler estimation. |
false |
| neighborCells | []object |
neighborCells lists neighbor NTN cells for measurement/handover.
OCUDU YAML renders as "ncells:" for compatibility. |
false |
| ntnGatewayLocation | object |
ntnGatewayLocation specifies the NTN gateway (ground station) coordinates. |
false |
| ntnUlSyncValidityDur | integer |
ntnUlSyncValidityDur sets the UL synchronization validity duration in seconds (SIB19
ntn-Config-r17 ntn-UlSyncValidityDuration). A UE runs timer T430 = this duration from the SIB19
epochTime (TS 38.331 §5.2.2.4.21) and, on T430 expiry (§5.2.2.6), deems UL sync lost and re-acquires
SIB19; the resulting cessation of uplink transmission is the lower-layer MAC/PHY behaviour (TS 38.321 /
TS 38.213 — T430 itself is a 38.331 timer). Unset is NOT "no validity": the operator applies 5 s (the
runtime push sends it, and OCUDU's own config default is 5 s), so the advisory evaluates an unset field
against 5 s too. Two deployment-sizing rules follow (see docs/ntn-ul-sync-timing.md):
(1) the SIB19 broadcast period (cellOverrides.sibSchedule.siPeriod) must be shorter than this value so
the UE can re-read SIB19 in time — the operator raises a SIB19CadenceSane=False Warning when it is not
(gated on the gNB re-anchoring its SIB19 epoch; see provider.sib19EpochMode);
(2) the ephemeris re-push cadence vs this value is a NON-issue on OCUDU (the primary provider re-anchors
the broadcast SIB19 epochTime to the SI-window end on each regeneration, so validity self-renews) — it
would only matter for a provider that pins the broadcast epochTime to the pushed timestamp, where it is
a deployment-sizing responsibility (not auto-enforced). Enum: 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 120, 180, 240, 900 |
false |
| payloadType | enum |
payloadType specifies the satellite payload architecture. Enum: transparent, regenerative Default: transparent |
false |
| polarization | object |
polarization specifies the antenna polarization for downlink and uplink.
Per 3GPP TS 38.331 SIB19, ntn-PolarizationDL-r17 and ntn-PolarizationUL-r17
are independent IEs. OCUDU collapses them under a single `polarization:` map
with `dl:` / `ul:` sub-keys, matching this CRD layout. Validations: |
false |
| referenceLocation | object |
referenceLocation defines the NTN cell reference location. |
false |
| satSwitchWithResync | object |
satSwitchWithResync provides satellite switch handover hints to UEs during
satellite-to-satellite transitions. 3GPP Release 18 SIB19 field. |
false |
| tService | integer |
tService sets the expected NTN service duration in seconds. Minimum: 1 |
false |
| taCommon | integer |
taCommon sets the common Timing Advance value (0-66485757). Default: 0 Minimum: 0 Maximum: 6.6485756e+07 |
false |
| taInfo | object |
taInfo provides extended Timing Advance parameters per 3GPP TS 38.213.
When set, taInfo.taCommon takes precedence over the top-level taCommon field. |
false |
| taReport | boolean |
taReport enables UE TA reporting. |
false |
ephemerisECEF defines the satellite position and velocity in ECEF coordinates. Mutually exclusive with ephemerisOrbital.
| Name | Type | Description | Required |
|---|---|---|---|
| posX | integer |
posX is the X position in 1.3 m/LSB codepoints (3GPP positionX-r17,
-33554432 to 33554431). The operator emits posX × 1.3 as metres to OCUDU. Minimum: -3.3554432e+07 Maximum: 3.355443e+07 |
true |
| posY | integer |
posY is the Y position in 1.3 m/LSB codepoints (-33554432 to 33554431). Minimum: -3.3554432e+07 Maximum: 3.355443e+07 |
true |
| posZ | integer |
posZ is the Z position in 1.3 m/LSB codepoints (-33554432 to 33554431). Minimum: -3.3554432e+07 Maximum: 3.355443e+07 |
true |
| velX | integer |
velX is the X velocity in 0.06 m/s/LSB codepoints (3GPP velocityVX-r17,
-131072 to 131071; 0 for GEO). The operator emits velX × 0.06 as m/s. Default: 0 Minimum: -131072 Maximum: 131071 |
false |
| velY | integer |
velY is the Y velocity in 0.06 m/s/LSB codepoints (-131072 to 131071; 0 for GEO). Default: 0 Minimum: -131072 Maximum: 131071 |
false |
| velZ | integer |
velZ is the Z velocity in 0.06 m/s/LSB codepoints (-131072 to 131071; 0 for GEO). Default: 0 Minimum: -131072 Maximum: 131071 |
false |
ephemerisOrbital defines the satellite orbit using Keplerian elements. Mutually exclusive with ephemerisECEF. Preferred for LEO satellites where source data is in OMM/TLE form (CelesTrak, SpaceTrack).
| Name | Type | Description | Required |
|---|---|---|---|
| argOfPeriapsis | integer |
argOfPeriapsis is the argument of periapsis in 1e-4 degrees (0-3600000). Minimum: 0 Maximum: 3.6e+06 |
true |
| eccentricity | integer |
eccentricity is the orbital eccentricity scaled by 1e6 (0-15005). The
operator emits eccentricity × 1e-6; OCUDU accepts e ≤ 0.01500510825. Minimum: 0 Maximum: 15005 |
true |
| inclination | integer |
inclination is the orbital inclination in 1e-4 degrees; the operator emits
inclination × π/1.8e6 as radians. OCUDU's orbital ephemeris accepts only
[0°, 90°] (0 to +π/2 rad), so inclinations above 90° (e.g. sun-synchronous
~98°, retrograde) are NOT representable via the orbital path — use
ephemerisECEF (SGP4 state vector) for those. Max is 900000 (90°). Minimum: 0 Maximum: 900000 |
true |
| meanAnomaly | integer |
meanAnomaly is the mean anomaly in 1e-4 degrees (0-3600000). Minimum: 0 Maximum: 3.6e+06 |
true |
| rightAscension | integer |
rightAscension is the right ascension of the ascending node in 1e-4 degrees (0-3600000). Minimum: 0 Maximum: 3.6e+06 |
true |
| semiMajorAxis | integer |
semiMajorAxis is the semi-major axis in metres, emitted as-is to OCUDU
(which accepts 6500000-42998632 m). Minimum: 6.5e+06 Maximum: 4.2998632e+07 |
true |
epochTime defines the SFN/subframe reference for NTN timing alignment.
| Name | Type | Description | Required |
|---|---|---|---|
| sfn | integer |
sfn is the System Frame Number (0-1023). Minimum: 0 Maximum: 1023 |
true |
| subframeNumber | integer |
subframeNumber is the subframe within the SFN (0-9). Minimum: 0 Maximum: 9 |
true |
feederLinkInfo provides feeder link parameters for Doppler compensation.
| Name | Type | Description | Required |
|---|---|---|---|
| dlFreqHz | integer |
dlFreqHz is the downlink frequency in Hz. Required when feederLinkInfo is set. Format: int64 Minimum: 1 |
true |
| enableDopplerCompensation | boolean |
enableDopplerCompensation enables feeder link Doppler compensation. |
true |
| ulFreqHz | integer |
ulFreqHz is the uplink frequency in Hz. Required when feederLinkInfo is set. Format: int64 Minimum: 1 |
true |
movingRefLocation defines the Earth-moving reference location for LEO NTN cells. 3GPP Release 18 SIB19 field. Used by UEs for timing/Doppler estimation.
| Name | Type | Description | Required |
|---|---|---|---|
| latitude | integer |
latitude in 1e-4 degrees (-900000 to 900000 = -90° to 90°). Minimum: -900000 Maximum: 900000 |
true |
| longitude | integer |
longitude in 1e-4 degrees (-1800000 to 1800000 = -180° to 180°). Minimum: -1.8e+06 Maximum: 1.8e+06 |
true |
NTNNeighborCell describes a neighbor NTN cell.
| Name | Type | Description | Required |
|---|---|---|---|
| physicalCellID | integer |
physicalCellID of the neighbor (0-1007). Minimum: 0 Maximum: 1007 |
true |
| frequency | integer |
frequency is the neighbor cell's ARFCN (NR-ARFCN, always >= 1). Minimum: 1 |
false |
ntnGatewayLocation specifies the NTN gateway (ground station) coordinates.
| Name | Type | Description | Required |
|---|---|---|---|
| altitude | integer |
altitude in metres above sea level. Required when ntnGatewayLocation is set. |
true |
| latitude | integer |
latitude in 1e-4 degrees (-900000 to 900000). Minimum: -900000 Maximum: 900000 |
true |
| longitude | integer |
longitude in 1e-4 degrees (-1800000 to 1800000). Minimum: -1.8e+06 Maximum: 1.8e+06 |
true |
polarization specifies the antenna polarization for downlink and uplink.
Per 3GPP TS 38.331 SIB19, ntn-PolarizationDL-r17 and ntn-PolarizationUL-r17
are independent IEs. OCUDU collapses them under a single polarization: map
with dl: / ul: sub-keys, matching this CRD layout.
| Name | Type | Description | Required |
|---|---|---|---|
| dl | enum |
dl is the downlink polarization broadcast in SIB19 ntn-PolarizationDL-r17. Enum: rhcp, lhcp, linear |
false |
| ul | enum |
ul is the uplink polarization broadcast in SIB19 ntn-PolarizationUL-r17. Enum: rhcp, lhcp, linear |
false |
referenceLocation defines the NTN cell reference location.
| Name | Type | Description | Required |
|---|---|---|---|
| latitude | integer |
latitude in 1e-4 degrees (-900000 to 900000). Minimum: -900000 Maximum: 900000 |
true |
| longitude | integer |
longitude in 1e-4 degrees (-1800000 to 1800000). Minimum: -1.8e+06 Maximum: 1.8e+06 |
true |
satSwitchWithResync provides satellite switch handover hints to UEs during satellite-to-satellite transitions. 3GPP Release 18 SIB19 field.
| Name | Type | Description | Required |
|---|---|---|---|
| ntnConfig | object |
ntnConfig is the target satellite's NTN configuration after the switch.
Required: OCUDU rejects a sat_switch_with_resync that has no ntn_cfg. Validations: |
true |
| epochUnixMs | integer |
epochUnixMs is the reference epoch for the target assistance info, in Unix
milliseconds. 0 omits the field. Unlike the serving-cell epoch, OCUDU does
not require the sat-switch epoch to be in the future. Format: int64 |
false |
| gatewayLocation | object |
gatewayLocation is the target satellite's NTN gateway (feeder) location,
emitted as OCUDU's ntn_gateway_location geodetic coordinates. |
false |
| ssbTimeOffsetSubframes | integer |
ssbTimeOffsetSubframes is the SSB time offset in subframes (0-159), mapping
to OCUDU's ssb_time_offset_sf. Minimum: 0 Maximum: 159 |
false |
| tServiceStartUnixMs | integer |
tServiceStartUnixMs is when the target satellite starts serving, in Unix
milliseconds. 0 omits the field. Format: int64 |
false |
ntnConfig is the target satellite's NTN configuration after the switch. Required: OCUDU rejects a sat_switch_with_resync that has no ntn_cfg.
| Name | Type | Description | Required |
|---|---|---|---|
| cellSpecificKoffset | integer |
cellSpecificKoffset is the target cell-specific K_offset in milliseconds,
same semantics as NTNParams.cellSpecificKoffset: 1-1023, with Minimum 1
because OCUDU rejects 0. Omit the field to leave it unset. Minimum: 1 Maximum: 1023 |
false |
| ephemerisECEF | object |
ephemerisECEF is the target satellite's ECEF state vector.
Mutually exclusive with ephemerisOrbital. |
false |
| ephemerisOrbital | object |
ephemerisOrbital is the target satellite's Keplerian elements.
Mutually exclusive with ephemerisECEF. |
false |
| kMac | integer |
kMac is the MAC-CE scheduling offset k_mac (3GPP kmac-r17, INTEGER 1..512).
It tunes the k-offset applied to MAC CE contention-based resolution so UE
MAC feedback stays time-aligned with the satellite round-trip; distinct from
cellSpecificKoffset (PUSCH/PDSCH offset).
This is the ONLY OCUDU surface that accepts k_mac (issue #52): the runtime ntn_config_update command's sat_switch_with_resync.ntn_cfg. k_mac is NOT in OCUDU's bootstrap YAML on any cell (serving, neighbor, or satswitch), so the serving-cell static config remains 7/8 on the ntn_config field set by design. The 1..512 bound here is LOAD-BEARING: OCUDU's runtime update path does not
range-check k_mac (verified against a live gNB — it accepts out-of-range
values that would then violate the ASN.1 kmac-r17 constraint), so this CRD
validation is the only guard keeping a 3GPP-invalid k_mac off the wire. |
false |
| ntnUlSyncValidityDur | integer |
ntnUlSyncValidityDur is the target UL-sync validity duration in seconds.
OCUDU keys this ntn_ul_sync_validity_dur inside ntn_cfg — deliberately
distinct from the serving-cell ntn_ul_sync_validity_duration key. Enum: 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 120, 180, 240, 900 |
false |
| taInfo | object |
taInfo provides the target satellite's timing-advance parameters. The
runtime ntn_cfg accepts only ta_common / ta_common_drift /
ta_common_drift_variant — NOT ta_common_offset (that key is YAML-only), so
taInfo.taCommonOffset is ignored when pushed here. |
false |
| taReport | boolean |
taReport enables UE TA reporting for the target satellite. |
false |
ephemerisECEF is the target satellite's ECEF state vector. Mutually exclusive with ephemerisOrbital.
| Name | Type | Description | Required |
|---|---|---|---|
| posX | integer |
posX is the X position in 1.3 m/LSB codepoints (3GPP positionX-r17,
-33554432 to 33554431). The operator emits posX × 1.3 as metres to OCUDU. Minimum: -3.3554432e+07 Maximum: 3.355443e+07 |
true |
| posY | integer |
posY is the Y position in 1.3 m/LSB codepoints (-33554432 to 33554431). Minimum: -3.3554432e+07 Maximum: 3.355443e+07 |
true |
| posZ | integer |
posZ is the Z position in 1.3 m/LSB codepoints (-33554432 to 33554431). Minimum: -3.3554432e+07 Maximum: 3.355443e+07 |
true |
| velX | integer |
velX is the X velocity in 0.06 m/s/LSB codepoints (3GPP velocityVX-r17,
-131072 to 131071; 0 for GEO). The operator emits velX × 0.06 as m/s. Default: 0 Minimum: -131072 Maximum: 131071 |
false |
| velY | integer |
velY is the Y velocity in 0.06 m/s/LSB codepoints (-131072 to 131071; 0 for GEO). Default: 0 Minimum: -131072 Maximum: 131071 |
false |
| velZ | integer |
velZ is the Z velocity in 0.06 m/s/LSB codepoints (-131072 to 131071; 0 for GEO). Default: 0 Minimum: -131072 Maximum: 131071 |
false |
ephemerisOrbital is the target satellite's Keplerian elements. Mutually exclusive with ephemerisECEF.
| Name | Type | Description | Required |
|---|---|---|---|
| argOfPeriapsis | integer |
argOfPeriapsis is the argument of periapsis in 1e-4 degrees (0-3600000). Minimum: 0 Maximum: 3.6e+06 |
true |
| eccentricity | integer |
eccentricity is the orbital eccentricity scaled by 1e6 (0-15005). The
operator emits eccentricity × 1e-6; OCUDU accepts e ≤ 0.01500510825. Minimum: 0 Maximum: 15005 |
true |
| inclination | integer |
inclination is the orbital inclination in 1e-4 degrees; the operator emits
inclination × π/1.8e6 as radians. OCUDU's orbital ephemeris accepts only
[0°, 90°] (0 to +π/2 rad), so inclinations above 90° (e.g. sun-synchronous
~98°, retrograde) are NOT representable via the orbital path — use
ephemerisECEF (SGP4 state vector) for those. Max is 900000 (90°). Minimum: 0 Maximum: 900000 |
true |
| meanAnomaly | integer |
meanAnomaly is the mean anomaly in 1e-4 degrees (0-3600000). Minimum: 0 Maximum: 3.6e+06 |
true |
| rightAscension | integer |
rightAscension is the right ascension of the ascending node in 1e-4 degrees (0-3600000). Minimum: 0 Maximum: 3.6e+06 |
true |
| semiMajorAxis | integer |
semiMajorAxis is the semi-major axis in metres, emitted as-is to OCUDU
(which accepts 6500000-42998632 m). Minimum: 6.5e+06 Maximum: 4.2998632e+07 |
true |
taInfo provides the target satellite's timing-advance parameters. The runtime ntn_cfg accepts only ta_common / ta_common_drift / ta_common_drift_variant — NOT ta_common_offset (that key is YAML-only), so taInfo.taCommonOffset is ignored when pushed here.
| Name | Type | Description | Required |
|---|---|---|---|
| taCommon | integer |
taCommon is the common Timing Advance value (0-66485757). Required when
taInfo is set — explicitly provide 0 for GEO satellites. Minimum: 0 Maximum: 6.6485756e+07 |
true |
| taCommonDrift | integer |
taCommonDrift is the TA drift rate in 3GPP codepoints (ta-CommonDrift-r17,
-257303 to 257303). The operator emits taCommonDrift × 2e-4 as µs/s
(OCUDU accepts ±51.4606 µs/s). Minimum: -257303 Maximum: 257303 |
false |
| taCommonDriftVariant | integer |
taCommonDriftVariant is the TA drift-rate variant in codepoints
(ta-CommonDriftVariant-r17, 0 to 28949). Emitted × 2e-5 as µs/s²
(OCUDU accepts 0-0.57898 µs/s²). Minimum: 0 Maximum: 28949 |
false |
| taCommonOffset | integer |
taCommonOffset is an additional common-TA offset in codepoints (same
0.004072 µs granularity as taCommon; 0 to 2455796 maps to OCUDU's 0-10000 µs). Minimum: 0 Maximum: 2.455795e+06 |
false |
gatewayLocation is the target satellite's NTN gateway (feeder) location, emitted as OCUDU's ntn_gateway_location geodetic coordinates.
| Name | Type | Description | Required |
|---|---|---|---|
| altitude | integer |
altitude in metres above sea level. Required when ntnGatewayLocation is set. |
true |
| latitude | integer |
latitude in 1e-4 degrees (-900000 to 900000). Minimum: -900000 Maximum: 900000 |
true |
| longitude | integer |
longitude in 1e-4 degrees (-1800000 to 1800000). Minimum: -1.8e+06 Maximum: 1.8e+06 |
true |
taInfo provides extended Timing Advance parameters per 3GPP TS 38.213. When set, taInfo.taCommon takes precedence over the top-level taCommon field.
| Name | Type | Description | Required |
|---|---|---|---|
| taCommon | integer |
taCommon is the common Timing Advance value (0-66485757). Required when
taInfo is set — explicitly provide 0 for GEO satellites. Minimum: 0 Maximum: 6.6485756e+07 |
true |
| taCommonDrift | integer |
taCommonDrift is the TA drift rate in 3GPP codepoints (ta-CommonDrift-r17,
-257303 to 257303). The operator emits taCommonDrift × 2e-4 as µs/s
(OCUDU accepts ±51.4606 µs/s). Minimum: -257303 Maximum: 257303 |
false |
| taCommonDriftVariant | integer |
taCommonDriftVariant is the TA drift-rate variant in codepoints
(ta-CommonDriftVariant-r17, 0 to 28949). Emitted × 2e-5 as µs/s²
(OCUDU accepts 0-0.57898 µs/s²). Minimum: 0 Maximum: 28949 |
false |
| taCommonOffset | integer |
taCommonOffset is an additional common-TA offset in codepoints (same
0.004072 µs granularity as taCommon; 0 to 2455796 maps to OCUDU's 0-10000 µs). Minimum: 0 Maximum: 2.455795e+06 |
false |
provider specifies which NTN backend to configure.
| Name | Type | Description | Required |
|---|---|---|---|
| type | enum |
type is the provider type. Currently only "ocudu" is supported. Enum: ocudu |
true |
| endpoint | string |
endpoint is the provider-specific endpoint (e.g., O1 NETCONF address). |
false |
| namespace | string |
namespace where the provider resources (e.g., OCUDU gNB) are deployed. |
false |
| remoteControl | object |
remoteControl configures the gNB remote_control WebSocket for live NTN
config push. When set together with spec.cellID, the operator pushes runtime
ntn_config_update commands; otherwise it uses the ConfigMap path only. |
false |
| sib19EpochMode | enum |
sib19EpochMode declares how this gNB build derives the BROADCAST SIB19 epochTime — which the operator
cannot observe at runtime, but which decides whether the SIB19-cadence advisory (SIB19CadenceSane) is
meaningful. "reanchored": each periodic SIB19 regeneration refreshes the broadcast epoch, so a UE
re-acquiring SIB19 within the validity window advances its T430 deadline — the advisory applies.
"pinned": the gNB re-broadcasts a fixed epoch, so re-acquisition does not extend validity and the
cadence check would mislead — the operator then expresses NO opinion (no SIB19CadenceSane condition).
Unset falls back to the provider-type default: OCUDU is VERIFIED to re-anchor at the revision recorded
in docs/ntn-ul-sync-timing.md, so unset+ocudu ⇒ reanchored. Set this explicitly (e.g. "pinned") if you
run a gNB build whose SIB19 epoch behaviour differs from that verified revision — a doc note alone
cannot stop a changed build from being trusted, so this is the enforceable override. Enum: reanchored, pinned |
false |
remoteControl configures the gNB remote_control WebSocket for live NTN config push. When set together with spec.cellID, the operator pushes runtime ntn_config_update commands; otherwise it uses the ConfigMap path only.
| Name | Type | Description | Required |
|---|---|---|---|
| endpoint | string |
endpoint is host:port of the gNB remote_control server — a hostname/IPv4
("127.0.0.1:8001") or a bracketed IPv6 literal ("[::1]:8001") for dual-stack
clusters. The provider prepends ws://, so include NEITHER a scheme nor a path
— a value like "ws://host:8001" would dial "ws://ws://host:8001" and fail.
Validation is layered: the pattern enforces the bare host:port shape with a
DNS-1123 hostname or bracketed IPv6, and CEL rules enforce the port range
(1-65535), that a bracketed host is a valid IP, that an all-numeric host is a
valid IPv4 (so "999.999.999.999:1" is rejected, not treated as a hostname), and
that a DNS host obeys the RFC 1035 length limits (whole name <= 253, each label
1-63) — a permanent admission error beats a silent tight-requeue on a mistyped
value. The pattern alone cannot bound the label/host length (a regex quantifier
would, but the DNS-1123 label form makes that unreadable), so CEL carries it.
Shape validation does NOT restrict WHICH host the operator will dial; the endpoint is
CR-author-controlled, so confining it is an admin egress control (SSRF), not a CRD rule.
Set the operator flag --remote-control-allowed-endpoint-hosts to permit only sanctioned
gNB hosts for the runtime push (empty = any, backward compatible), and pair it with the
operator egress NetworkPolicy (config/network-policy/allow-egress-traffic.yaml). See #299. |
true |
| tls | object |
tls, when set, secures the runtime push: the provider dials wss:// (TLS)
instead of plaintext ws:// and authenticates with the material in the
referenced Secret. Omit it to keep the plaintext ws:// behavior (N-12). |
false |
tls, when set, secures the runtime push: the provider dials wss:// (TLS) instead of plaintext ws:// and authenticates with the material in the referenced Secret. Omit it to keep the plaintext ws:// behavior (N-12).
| Name | Type | Description | Required |
|---|---|---|---|
| mode | enum |
mode selects the transport-security posture:
"tls" — dial wss://, verify the server certificate, and (if the Secret
carries a token) send it as an Authorization: Bearer header.
"mtls" — additionally present a client certificate (mutual TLS); the
Secret MUST then carry tls.crt + tls.key. Enum: tls, mtls |
true |
| secretName | string |
secretName is the Secret (in this NTNCellConfig's namespace) holding the TLS
trust and auth material. Recognized keys: "ca.crt" (PEM CA to verify the
gNB/proxy server certificate — omit to use the system roots), "token" (the
shared secret sent as Authorization: Bearer — optional), and, for mode=mtls,
"tls.crt" + "tls.key" (the client certificate/key). A bare shared secret is
replayable, so it is only ever sent over the wss:// (TLS) connection.
"ca.crt" is REQUIRED whenever "token" is set: endpoint is caller-controlled, so a token validated only by the public roots could be delivered to any host whose owner can obtain a publicly-trusted certificate. Pin the gNB's own CA. mode=mtls without ca.crt is still permitted — it proves a key rather than sending one. SECURITY: the Secret's owner must opt it in for remote-control use with the label
"ntn.operators.dev/remote-control-credential: true", and a Kubernetes API
credential (a service-account or bootstrap-token Secret) is refused. This is a
mitigation, not a full authorization boundary: the opt-in is namespace-scoped, so
ANY NTNCellConfig in the namespace may use a labelled Secret. Do not grant
NTNCellConfig write to principals who should not be able to use every labelled
remote-control credential in that namespace. |
true |
| serverName | string |
serverName overrides the TLS ServerName (SNI) verified against the server
certificate's SubjectAltNames. Defaults to the endpoint host. Set it when the
gNB/proxy certificate's SAN does not match the dialed host (e.g. an IP
endpoint fronted by a DNS-named certificate). |
false |
cellID identifies the OCUDU cell (plmn + nci) that runtime remote commands target. Required when provider.remoteControl is set; the value must match the cell the gNB booted with. Unset ⇒ ConfigMap bootstrap path only.
| Name | Type | Description | Required |
|---|---|---|---|
| nci | integer |
nci is the 36-bit NR Cell Identity (0 to 2^36-1). Format: int64 Minimum: 0 Maximum: 6.8719476735e+10 |
true |
| plmn | string |
plmn is the cell's PLMN, 5 or 6 digits (e.g. "00101"). |
true |
cellOverrides allows fine-tuning PUCCH, PDSCH, PRACH, and RRC parameters.
| Name | Type | Description | Required |
|---|---|---|---|
| pdschMaxHarqRetxs | integer |
pdschMaxHarqRetxs sets the max HARQ retransmissions (0 = disabled for NTN). Default: 0 |
false |
| prachMaxMsg3HarqRetx | integer |
prachMaxMsg3HarqRetx sets the max msg3 HARQ retransmissions. Default: 0 |
false |
| rrcGuardTimeMs | integer |
rrcGuardTimeMs sets the RRC procedure guard time in ms. Default: 12800 |
false |
| sibSchedule | object |
sibSchedule tunes SIB19 broadcast scheduling. Any unset sub-field
falls back to the defaults (siWindowLength=5, siPeriod=16,
siWindowPosition=2). Tune when PDCCH capacity is tight or when
SIB19 broadcast cadence needs to track short ntn-UlSyncValidityDur. |
false |
sibSchedule tunes SIB19 broadcast scheduling. Any unset sub-field falls back to the defaults (siWindowLength=5, siPeriod=16, siWindowPosition=2). Tune when PDCCH capacity is tight or when SIB19 broadcast cadence needs to track short ntn-UlSyncValidityDur.
| Name | Type | Description | Required |
|---|---|---|---|
| siPeriod | integer |
siPeriod is the SIB19 broadcast period in radio frames (1 frame = 10 ms; unset defaults to 16).
Shorter periods keep UEs' NTN assistance fresh but cost air time. It should be shorter than
ntn.ntnUlSyncValidityDur so a UE can re-acquire SIB19 within the UL-sync validity window — an
engineering consequence of the TS 38.331 §5.2.2.4.21 re-acquisition requirement, not a normative
38.331 constraint; the operator raises a SIB19CadenceSane=False Warning when fewer than two SIB19
broadcasts fit inside that window (see docs/ntn-ul-sync-timing.md). Enum: 8, 16, 32, 64, 128, 256, 512 |
false |
| siWindowLength | integer |
siWindowLength is the SI window length in slots. OCUDU accepts
the standard set; picking a larger value increases PDCCH pressure. Enum: 5, 10, 20, 40, 80, 160, 320, 640, 1280 |
false |
| siWindowPosition | integer |
siWindowPosition is SIB19's slot offset within the SI period
(schedulingInfoList2-r17). It must be strictly greater than the number of
preceding schedulingInfoList entries; the emitter always schedules one SIB2
(ID < 15) before SIB19, so the minimum is 2. Pointer so an explicit value is
distinguished from unset (which defaults to 2). Minimum: 2 Maximum: 79 |
false |
NTNCellConfigStatus defines the observed state of NTNCellConfig.
| Name | Type | Description | Required |
|---|---|---|---|
| appliedKoffset | integer |
appliedKoffset is the last successfully applied k-offset value. |
false |
| conditions | []object |
conditions represent the current state of the resource. |
false |
| configMapRef | string |
configMapRef is the name of the ConfigMap containing the generated config. |
false |
| lastPushedSatSwitchDigest | string |
lastPushedSatSwitchDigest is the content digest of the sat_switch_with_resync last delivered
to the gNB by the runtime push. The switch is re-attached to a runtime update only when this
changes, so a (possibly non-idempotent) MAC/RRC-resync command is not re-sent on every
ephemeris heartbeat (issue #207). Empty when no switch has been sent. |
false |
Condition contains details for one aspect of the current state of this API Resource.
| Name | Type | Description | Required |
|---|---|---|---|
| lastTransitionTime | string |
lastTransitionTime is the last time the condition transitioned from one status to another.
This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. Format: date-time |
true |
| message | string |
message is a human readable message indicating details about the transition.
This may be an empty string. |
true |
| reason | string |
reason contains a programmatic identifier indicating the reason for the condition's last transition.
Producers of specific condition types may define expected values and meanings for this field,
and whether the values are considered a guaranteed API.
The value should be a CamelCase string.
This field may not be empty. |
true |
| status | enum |
status of the condition, one of True, False, Unknown. Enum: True, False, Unknown |
true |
| type | string |
type of condition in CamelCase or in foo.example.com/CamelCase. |
true |
| observedGeneration | integer |
observedGeneration represents the .metadata.generation that the condition was set based upon.
For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
with respect to the current state of the instance. Format: int64 Minimum: 0 |
false |
NTNSlice manages terrestrial-satellite network slice failover, QoS mapping, and session continuity for NTN enterprise services.
| Name | Type | Description | Required |
|---|---|---|---|
| apiVersion | string | ntn.operators.dev/v1alpha1 | true |
| kind | string | NTNSlice | true |
| metadata | object | Refer to the Kubernetes API documentation for the fields of the `metadata` field. | true |
| spec | object |
NTNSliceSpec defines the desired state of an NTN network slice
with terrestrial-satellite failover policy. Validations: |
true |
| status | object |
|
false |
NTNSliceSpec defines the desired state of an NTN network slice with terrestrial-satellite failover policy.
| Name | Type | Description | Required |
|---|---|---|---|
| failoverPolicy | object |
failoverPolicy defines when and how to switch between paths. Validations: |
true |
| satellitePath | object |
satellitePath defines the failover satellite connectivity. |
true |
| tenant | string |
tenant is the organization or entity that owns this slice. |
true |
| terrestrialPath | object |
terrestrialPath defines the primary terrestrial connectivity. |
true |
| billing | object |
billing defines CDR generation parameters. |
false |
| metricsSource | object |
metricsSource selects where the failover engine reads path quality
metrics (RSRP, latency, packet loss) from. When omitted, the
controller falls back to annotation-driven simulation for backward
compatibility with existing development deployments. Validations: |
false |
| qosMapping | object |
qosMapping defines QoS parameter mapping between paths. |
false |
| security | object |
security defines handover security requirements. |
false |
failoverPolicy defines when and how to switch between paths.
| Name | Type | Description | Required |
|---|---|---|---|
| triggers | []string |
triggers defines conditions that initiate failover (OR logic).
Format: "metric operator value" (e.g., "rsrp < -120").
Validated at admission by the XValidation rule on this type and at runtime by
the failover engine (pkg/slice.ParseTrigger).
Order is intentionally not significant; set merge semantics are desired. |
true |
| confirmationSamples | integer |
confirmationSamples is the number of CONSECUTIVE reconcile samples on which
the terrestrial triggers must fire before a failover to satellite is taken
(production load balancers such as AWS ALB / GCP count consecutive, not
windowed, probe results). It absorbs a single-sample blip so one noisy
reading does not trip a switch. 1 (the default when unset) preserves the
prior immediate-failover behavior; a value of N delays failover by up to
(N-1) reconcile intervals. The confirmation counter is kept in memory and
resets on any healthy reliable sample; losing it on a controller restart or
leader-election handoff only re-requires confirmation (a DELAY), never causes
a spurious switch. Format: int32 Minimum: 1 Maximum: 10 |
false |
| hysteresisMargin | string |
hysteresisMargin is a dead-band applied to trigger thresholds
during switchback evaluation, preventing flapping when metrics
oscillate near the threshold. The value uses the same unit as
the trigger (dB for RSRP, ms for latency, percent for packetLoss).
Example: with trigger "rsrp < -120" and hysteresisMargin "10",
failover fires at RSRP < -120, but switchback requires RSRP >= -110. |
false |
| minTerrestrialDwell | string |
minTerrestrialDwell is the minimum time the terrestrial path must be held
after a switchback before another failover to satellite may be taken. It
bounds sub-minute ping-pong after a hand-back. It is a soft, bounded delay
— a genuinely failing terrestrial still fails over once the dwell elapses,
so it never indefinitely blocks a real failover. 0 (the default) disables
it; 30s–120s is a sane range relative to a LEO pass. A negative value would
silently disable the dwell (elapsed < negative is never true), so admission
bounds it to [0s, 24h]. Validations: |
false |
| sessionContinuity | boolean |
sessionContinuity is accepted for forward compatibility but is NOT enforced by this
build: no runtime session preservation is performed during a path switch, so active
sessions may drop on failover regardless of this value. It is retained so the intent
stays expressible and a future release can honor it (#69); do not rely on it for
session survival today. The default stays true only to preserve the field's prior
admission behavior — it turns no preservation on. Default: true |
false |
| switchbackDelay | string |
switchbackDelay is how long to wait after terrestrial recovers
before switching back (prevents flapping). A negative value is meaningless
here, so admission bounds it to [0s, 24h] (24h is a fat-finger ceiling, far
above any LEO-pass-relative value). Validations: Default: 60s |
false |
satellitePath defines the failover satellite connectivity.
| Name | Type | Description | Required |
|---|---|---|---|
| ephemerisRef | string |
ephemerisRef is the name of the SatelliteEphemeris resource used to determine
satellite pass availability. The referenced ephemeris is treated as a
CONSTELLATION POOL: the satellite path is available whenever ANY tracked member
is overhead and deliverable — the slice is deliberately not pinned to one NORAD,
because LEO members hand over. Which member a given cell broadcasts is
NTNCellConfig.ephemerisNoradID's concern, not this path's. See ADR-0008. |
true |
| priority | enum |
priority is the path priority. Enum: primary, failover |
true |
| provider | string |
provider is the network operator name (e.g., "chunghwa-telecom"). |
true |
| apn | string |
apn is the Access Point Name. |
false |
terrestrialPath defines the primary terrestrial connectivity.
| Name | Type | Description | Required |
|---|---|---|---|
| priority | enum |
priority is the path priority. Enum: primary, failover |
true |
| provider | string |
provider is the network operator name (e.g., "chunghwa-telecom"). |
true |
| apn | string |
apn is the Access Point Name. |
false |
billing defines CDR generation parameters.
| Name | Type | Description | Required |
|---|---|---|---|
| satelliteRate | enum |
satelliteRate is the charging model for satellite path. Enum: per-volume, per-time, per-minute, flat |
false |
| terrestrialRate | enum |
terrestrialRate is the charging model for terrestrial path. Enum: per-volume, per-time, flat |
false |
metricsSource selects where the failover engine reads path quality metrics (RSRP, latency, packet loss) from. When omitted, the controller falls back to annotation-driven simulation for backward compatibility with existing development deployments.
| Name | Type | Description | Required |
|---|---|---|---|
| prometheus | object |
prometheus configures the Prometheus HTTP API backend.
Required when type is 'prometheus'. Validations: |
false |
| type | enum |
type is the backend kind. Enum: annotations, prometheus Default: annotations |
false |
prometheus configures the Prometheus HTTP API backend. Required when type is 'prometheus'.
| Name | Type | Description | Required |
|---|---|---|---|
| endpoint | string |
endpoint is the base URL of the Prometheus HTTP API. |
true |
| queries | object |
queries holds the PromQL expressions for each observable metric. |
true |
| queryTimeout | string |
queryTimeout limits the wall-clock time spent on each individual
PromQL fetch; the controller issues up to three fetches per
reconcile (one per metric), so the upper bound for a Read is
roughly 3x this value. Defaults to 2s when unset. Format: duration |
false |
queries holds the PromQL expressions for each observable metric.
| Name | Type | Description | Required |
|---|---|---|---|
| latencyMs | string |
latencyMs is a PromQL expression returning a scalar in milliseconds. |
false |
| packetLossPercent | string |
packetLossPercent is a PromQL expression returning a scalar in
percent (0-100). |
false |
| rsrpDbm | string |
rsrpDbm is a PromQL expression returning a scalar in dBm. |
false |
qosMapping defines QoS parameter mapping between paths.
| Name | Type | Description | Required |
|---|---|---|---|
| maxLatencyBudget | string |
maxLatencyBudget is the maximum acceptable latency including
satellite propagation delay. Format: duration Default: 150ms |
false |
| satelliteQCI | enum |
satelliteQCI is the QoS class for the satellite path. Enum: conversational, streaming, interactive, background, best-effort Default: best-effort |
false |
| terrestrial5QI | integer |
terrestrial5QI is the 5G QoS Identifier for the terrestrial path. Minimum: 1 Maximum: 255 |
false |
security defines handover security requirements.
| Name | Type | Description | Required |
|---|---|---|---|
| authOnHandover | enum |
authOnHandover defines authentication behavior during path switch. Enum: re-authenticate, continue Default: re-authenticate |
false |
| encryptionLevel | enum |
encryptionLevel specifies the encryption standard. Enum: AES-128, AES-256, SNOW3G, ZUC Default: AES-256 |
false |
| Name | Type | Description | Required |
|---|---|---|---|
| activePathType | enum |
activePathType is the currently active network path. Enum: terrestrial, satellite, unavailable |
false |
| appliedEncryption | string |
appliedEncryption is the encryption level in effect for the current path. |
false |
| appliedQoS | string |
appliedQoS summarizes the QoS mapping in effect for the current path. |
false |
| billingMode | string |
billingMode is the billing model active for the current path. |
false |
| conditions | []object |
conditions represent the current state of the slice. |
false |
| contactCandidate | object |
contactCandidate is the constellation member behind the current FailoverReady
evaluation: which satellite, seen from which ground station, over which window, and
on element data of what age. FailoverReady alone says a contact opportunity exists
but not which one, so an operator cannot tell a healthy handover between members
from the same member re-evaluated, and cannot audit the decision after the fact.
It is a CONTACT OPPORTUNITY, not delivered service: nothing here says the slice's
serving cell is configured for this member. Cleared when no candidate can be proven,
so a stale entry can never outlive the condition it explains (ADR-0008). |
false |
| failoverCount | integer |
failoverCount is the total number of failover events since creation. |
false |
| lastFailover | string |
lastFailover is the timestamp of the last failover event. Format: date-time |
false |
| lastSwitchbackTime | string |
lastSwitchbackTime is when the slice last switched back to terrestrial from an
available satellite (a quality-driven hand-back). It is persisted so the anti-flap
minimum-terrestrial-dwell survives a controller restart or leader-election handoff:
the in-memory flap clock resets on handoff, and without this a re-degradation within
the dwell window could switch to satellite earlier than the dwell intended. The other
flap clocks stay in-memory (losing them only delays a switch, never advances one). Format: date-time |
false |
| sessionCount | integer |
sessionCount is the number of active sessions on this slice. |
false |
Condition contains details for one aspect of the current state of this API Resource.
| Name | Type | Description | Required |
|---|---|---|---|
| lastTransitionTime | string |
lastTransitionTime is the last time the condition transitioned from one status to another.
This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. Format: date-time |
true |
| message | string |
message is a human readable message indicating details about the transition.
This may be an empty string. |
true |
| reason | string |
reason contains a programmatic identifier indicating the reason for the condition's last transition.
Producers of specific condition types may define expected values and meanings for this field,
and whether the values are considered a guaranteed API.
The value should be a CamelCase string.
This field may not be empty. |
true |
| status | enum |
status of the condition, one of True, False, Unknown. Enum: True, False, Unknown |
true |
| type | string |
type of condition in CamelCase or in foo.example.com/CamelCase. |
true |
| observedGeneration | integer |
observedGeneration represents the .metadata.generation that the condition was set based upon.
For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
with respect to the current state of the instance. Format: int64 Minimum: 0 |
false |
contactCandidate is the constellation member behind the current FailoverReady evaluation: which satellite, seen from which ground station, over which window, and on element data of what age. FailoverReady alone says a contact opportunity exists but not which one, so an operator cannot tell a healthy handover between members from the same member re-evaluated, and cannot audit the decision after the fact.
It is a CONTACT OPPORTUNITY, not delivered service: nothing here says the slice's serving cell is configured for this member. Cleared when no candidate can be proven, so a stale entry can never outlive the condition it explains (ADR-0008).
| Name | Type | Description | Required |
|---|---|---|---|
| noradID | integer |
noradID is the canonical satellite identity. satellite is a display label only. |
true |
| aos | string |
aos and los bound the pass window this candidate is currently inside. Format: date-time |
false |
| groundStation | string |
groundStation is the GroundStationLifecycle this window was predicted for. A pass is
only meaningful relative to an observer, so a candidate without one is not auditable. |
false |
| los | string |
Format: date-time |
false |
| propagatedEpochUnixMs | integer |
propagatedEpochUnixMs is the future epoch the state was propagated TO. Format: int64 |
false |
| satellite | string |
satellite is the externally sourced display name, bounded and rune-safe. Not unique:
correlate on noradID. |
false |
| selectionReason | string |
selectionReason names the rule that chose this candidate over its siblings, so the
choice is reproducible from the status alone. |
false |
| sourceEpochUnixMs | integer |
sourceEpochUnixMs is the epoch of the element set the window was propagated FROM —
the age that decides deliverability, not the propagation target below. Absent when no
propagatedStates entry matches noradID. Format: int64 |
false |
| validUntil | string |
validUntil is when this candidate stops being usable: the EARLIER of the pass ending
and its element set aging past the delivery freshness bound. Reporting only LOS would
promise a window the runtime push would refuse to use before it closes. Format: date-time |
false |
SatelliteEphemeris manages GP data fetching (OMM JSON from CelesTrak/SpaceTrack), orbital propagation (SGP4 via akhenakh/sgp4), and pass prediction for a set of satellites against ground stations.
Orbit-regime support: v1.0 is LEO-only. The propagator is the near-earth SGP4 model; element sets whose orbital period is >= 225 minutes (deep space — roughly MEO and above, e.g. O3b or GEO) are rejected rather than propagated into a wrong position, and surface as the UnsupportedOrbitRegime status condition. Multi-orbit (MEO/GEO) support is a v1.1 roadmap item.
| Name | Type | Description | Required |
|---|---|---|---|
| apiVersion | string | ntn.operators.dev/v1alpha1 | true |
| kind | string | SatelliteEphemeris | true |
| metadata | object | Refer to the Kubernetes API documentation for the fields of the `metadata` field. | true |
| spec | object |
SatelliteEphemerisSpec defines the desired state of SatelliteEphemeris. |
true |
| status | object |
SatelliteEphemerisStatus defines the observed state of SatelliteEphemeris. |
false |
SatelliteEphemerisSpec defines the desired state of SatelliteEphemeris.
| Name | Type | Description | Required |
|---|---|---|---|
| source | object |
source defines where to fetch GP (General Perturbations) data. Validations: |
true |
| passPrediction | object |
passPrediction configures automatic pass window computation. |
false |
| satellites | object |
satellites filters which satellites to track from the source. |
false |
source defines where to fetch GP (General Perturbations) data.
| Name | Type | Description | Required |
|---|---|---|---|
| refreshInterval | string |
refreshInterval is how often to re-fetch GP data.
CelesTrak updates every 2 hours; setting this below 2h wastes bandwidth. Format: duration Default: 4h |
true |
| type | enum |
type is the source type. Supported: "CelesTrak", "SpaceTrack". Enum: CelesTrak, SpaceTrack |
true |
| url | string |
url is the endpoint to fetch GP data from. Use https for any public
source: a cleartext http:// URL that resolves to a public IP is refused
at runtime (InsecureURL condition) because an on-path attacker could
inject forged OMM data that is propagated into SIB19. http:// is permitted
only for a private/in-cluster mirror (NetworkPolicy-protected).
For CelesTrak: https://celestrak.org/NORAD/elements/gp.php?GROUP=oneweb&FORMAT=JSON
For SpaceTrack: https://www.space-track.org/basicspacedata/query/class/gp/... |
true |
| credentials | object |
credentials is a reference to a Secret containing auth credentials
(required for SpaceTrack, optional for CelesTrak). |
false |
credentials is a reference to a Secret containing auth credentials (required for SpaceTrack, optional for CelesTrak).
| Name | Type | Description | Required |
|---|---|---|---|
| name | string |
name of the Secret. |
true |
| key | string |
key within the Secret data. Default: password |
false |
passPrediction configures automatic pass window computation.
| Name | Type | Description | Required |
|---|---|---|---|
| groundStations | []string |
groundStations is a list of GroundStationLifecycle resource names
to compute pass windows against. |
true |
| horizon | string |
horizon is how far into the future to predict passes. Default: 24h |
false |
| minElevation | string |
minElevation is the minimum elevation angle in degrees (string, e.g., "10"), in the
range [0, 90]: 0 is the geometric horizon and 90 the zenith. A negative or >90 mask
is physically meaningless (it would make every / no pass "usable"), so the pattern
rejects negatives and the CEL rule rejects values above 90. The pattern keeps the
pre-existing grammar otherwise (a trailing "." such as "10." stays valid — only the
leading "-" was removed) to avoid an unrelated API-grammar break. The bound is on the
parsed float64 value (the pipeline is float64), so a literal within ~half a ULP above
90 rounds to 90 and is accepted; the controller uses the float64 value. Validations: |
false |
satellites filters which satellites to track from the source.
| Name | Type | Description | Required |
|---|---|---|---|
| constellation | string |
constellation is DEPRECATED and performs no filtering at all — the controller
has never consumed it (neither server- nor client-side). Select a constellation
in the source URL instead (CelesTrak's GROUP= query parameter, e.g. GROUP=oneweb,
returns only that constellation's element sets) and/or list explicit noradIDs.
It stays accepted in v1alpha1; removal is deferred to a future versioned API
migration — a v1alpha2 that drops it must ship conversion so v1alpha1<->v1alpha2
round-trips losslessly, plus stored-object migration and storedVersions cleanup;
a version rename alone is not enough to safely drop the data.
Deprecated: select the constellation via source.url (GROUP=) or spec.satellites.noradIDs. |
false |
| noradIDs | []integer |
noradIDs is an explicit list of NORAD catalog IDs to track. |
false |
SatelliteEphemerisStatus defines the observed state of SatelliteEphemeris.
| Name | Type | Description | Required |
|---|---|---|---|
| conditions | []object |
conditions represent the current state of the resource. |
false |
| lastPassPredictionInputHash | string |
lastPassPredictionInputHash is a digest of the inputs that determine the pass windows: the
pass-prediction spec (ground stations, minElevation, horizon), the tracked NORAD selector, the
source identity, and each resolved ground station's identity/generation. The sweep re-runs
IMMEDIATELY when this changes — not only on the passPredictionInterval time cadence — so a
ground-station edit/add/delete, a selector change, or an elevation/horizon change re-predicts at
once instead of leaving stale windows for up to an interval (ADR 0006 / #234). Cleared whenever
the pass windows are invalidated (see invalidatePassPredictionStatus). |
false |
| lastPassPredictionTime | string |
lastPassPredictionTime is when the pass-window sweep last ran. The sweep runs on its own
lower cadence (passPredictionInterval), decoupled from the propagation heartbeat, so its
O(horizon x satellites x ground stations) cost stays out of the runtime-push epoch cadence
(ADR 0006 / #234). Persisted rather than in-memory so the "sweep is due" decision survives a
leader failover. Absent means the sweep has not run since this field appeared (or ever). Format: date-time |
false |
| lastUpdated | string |
lastUpdated is when the GP data was last successfully fetched. Format: date-time |
false |
| nextPassWindows | []object |
nextPassWindows contains upcoming contact opportunities. |
false |
| propagatedStates | []object |
propagatedStates holds SGP4-propagated ECEF state vectors (per satellite) at
the last refresh epoch, consumed by NTNCellConfig runtime ephemeris push (#176).
Capped (maxItems) to match the controller's maxPropagatedStates and stay well
under the etcd object-size limit. |
false |
| propagatedStatesInputHash | string |
propagatedStatesInputHash is a digest of the spec fields that determine WHICH
orbital data is fetched and WHICH satellites are propagated (source type/url and the
NORAD selector) — NOT the whole spec. It is stamped whenever the current
propagatedStates are (re)computed, from a fresh fetch or a valid cache entry for the
same upstream fetch identity (the OMM cache is keyed on source type+url, NOT on
.metadata.generation). The NTNCellConfig runtime-push consumer recomputes the hash from the live
spec and refuses to push when it differs — i.e. the persisted states were computed
under different propagation inputs (a source/selector edit whose re-propagate has
not yet succeeded), WITHOUT falsely invalidating on a pass-prediction-only edit
(#204-G1). Empty means the states predate this field (never re-propagated since
upgrade) or no successful reconcile yet. |
false |
| satelliteCount | integer |
satelliteCount is the number of satellites currently tracked. |
false |
| truncatedSatelliteCount | integer |
truncatedSatelliteCount is how many selected satellites were NOT propagated
because the maxPropagatedStates cap (128) had already been reached — the count
actually dropped by the cap, not merely (selected - 128), so satellites that
fail SGP4 propagation do not inflate it. ABSENT or 0 means nothing was dropped
(the field is omitempty). Narrow spec.satellites.noradIDs or the source URL's
GROUP= to eliminate it. Mirrored by the StatesTruncated condition; a Warning
StatesTruncated event fires once per transition into the truncated state. |
false |
Condition contains details for one aspect of the current state of this API Resource.
| Name | Type | Description | Required |
|---|---|---|---|
| lastTransitionTime | string |
lastTransitionTime is the last time the condition transitioned from one status to another.
This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. Format: date-time |
true |
| message | string |
message is a human readable message indicating details about the transition.
This may be an empty string. |
true |
| reason | string |
reason contains a programmatic identifier indicating the reason for the condition's last transition.
Producers of specific condition types may define expected values and meanings for this field,
and whether the values are considered a guaranteed API.
The value should be a CamelCase string.
This field may not be empty. |
true |
| status | enum |
status of the condition, one of True, False, Unknown. Enum: True, False, Unknown |
true |
| type | string |
type of condition in CamelCase or in foo.example.com/CamelCase. |
true |
| observedGeneration | integer |
observedGeneration represents the .metadata.generation that the condition was set based upon.
For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
with respect to the current state of the instance. Format: int64 Minimum: 0 |
false |
PassWindow represents a predicted contact opportunity between a satellite and ground station.
| Name | Type | Description | Required |
|---|---|---|---|
| aos | string |
aos is the Acquisition of Signal time (satellite rises above minElevation). Format: date-time |
true |
| groundStation | string |
groundStation is the name of the GroundStationLifecycle resource. |
true |
| los | string |
los is the Loss of Signal time (satellite drops below minElevation). Format: date-time |
true |
| maxElevation | string |
maxElevation is the peak elevation angle during the pass in degrees (string, e.g., "72.5"). |
true |
| satellite | string |
satellite is the satellite's display name (externally sourced OMM ObjectName), bounded and
rune-safe. The canonical identity is noradID; treat this as a label only. |
true |
| noradID | integer |
noradID is the satellite's NORAD catalog number — the canonical key that maps this window
to its propagatedStates entry, so a consumer (NTNSlice) can gate pass availability on the
backing element set's delivery freshness (same contract as the runtime push). 0 only for
windows written before this field existed (freshness then treated as unverifiable). |
false |
PropagatedState is a satellite state vector propagated (SGP4) to a specific epoch, in the 3GPP ECEF codepoint form the runtime ephemeris push consumes.
| Name | Type | Description | Required |
|---|---|---|---|
| ecef | object |
ecef is the propagated position/velocity in 3GPP codepoints. The provider
converts these to physical SI when pushing to OCUDU. |
true |
| epochUnixMs | integer |
epochUnixMs is the propagation epoch in Unix milliseconds (in the future,
as OCUDU's ntn_config_update requires). Format: int64 |
true |
| noradID | integer |
noradID is the satellite's NORAD catalog number, used by NTNCellConfig
(spec.ephemerisNoradID) to select which state to push. |
true |
| satellite | string |
satellite is the satellite name or object ID (bounded; the controller
truncates the externally-sourced name to this length). |
true |
| sourceEpochUnixMs | integer |
sourceEpochUnixMs is the epoch of the SOURCE orbital element set (the OMM EPOCH)
this state was propagated FROM, in Unix milliseconds. Unlike epochUnixMs (the
future propagation target), this is the element-set age used by the runtime-push
consumer to refuse pushing THIS satellite's drifting elements — a per-satellite
freshness bound, so a stale sibling in the same SatelliteEphemeris does not block
this one. The producer no longer emits a state whose source epoch it could not parse
(those satellites are skipped and surfaced via the SourceEpochRejected condition), so a 0
here is the zero value of an omitted field; the consumer treats a 0 epoch as the 1970
instant subject to the normal staleness bound, not as "unknown" or fresh. Format: int64 |
false |
ecef is the propagated position/velocity in 3GPP codepoints. The provider converts these to physical SI when pushing to OCUDU.
| Name | Type | Description | Required |
|---|---|---|---|
| posX | integer |
posX is the X position in 1.3 m/LSB codepoints (3GPP positionX-r17,
-33554432 to 33554431). The operator emits posX × 1.3 as metres to OCUDU. Minimum: -3.3554432e+07 Maximum: 3.355443e+07 |
true |
| posY | integer |
posY is the Y position in 1.3 m/LSB codepoints (-33554432 to 33554431). Minimum: -3.3554432e+07 Maximum: 3.355443e+07 |
true |
| posZ | integer |
posZ is the Z position in 1.3 m/LSB codepoints (-33554432 to 33554431). Minimum: -3.3554432e+07 Maximum: 3.355443e+07 |
true |
| velX | integer |
velX is the X velocity in 0.06 m/s/LSB codepoints (3GPP velocityVX-r17,
-131072 to 131071; 0 for GEO). The operator emits velX × 0.06 as m/s. Default: 0 Minimum: -131072 Maximum: 131071 |
false |
| velY | integer |
velY is the Y velocity in 0.06 m/s/LSB codepoints (-131072 to 131071; 0 for GEO). Default: 0 Minimum: -131072 Maximum: 131071 |
false |
| velZ | integer |
velZ is the Z velocity in 0.06 m/s/LSB codepoints (-131072 to 131071; 0 for GEO). Default: 0 Minimum: -131072 Maximum: 131071 |
false |