--- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.22.0 name: terdutservers.terdut.ryuvia.com spec: group: terdut.ryuvia.com names: kind: TerdutServer listKind: TerdutServerList plural: terdutservers singular: terdutserver scope: Namespaced versions: - additionalPrinterColumns: - jsonPath: .spec.replicas name: Replicas type: integer - jsonPath: .status.conditions[?(@.type=="Ready")].status name: Ready type: string - jsonPath: .status.conditions[?(@.type=="Ready")].reason name: Reason type: string name: v1alpha1 schema: openAPIV3Schema: description: TerdutServer is the Schema for the terdutservers API properties: apiVersion: description: |- APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: description: |- Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object spec: description: spec defines the desired state of TerdutServer properties: allowedTeams: description: |- allowedTeams gates cross-namespace TerdutTeams (DESIGN.md §4.6). Unused until TerdutTeam exists (ROADMAP.md Stage 2); present now so this CRD's schema doesn't need a breaking change to grow it later. properties: namespaces: description: |- AllowedTeamsNamespaces gates which namespaces a TerdutTeam may resolve a cross-namespace serverRef into this TerdutServer from (DESIGN.md §4.6). Same-namespace TerdutTeams are always allowed, regardless of this field. Modeled on Gateway API's Gateway.spec.allowedListeners.namespaces. properties: from: default: None description: |- from selects which namespaces may attach. Same is equivalent to None in effect (same-namespace is unrestricted either way) but kept for parity with the upstream enum this mirrors, and to make the policy self-documenting in a diff. enum: - None - Same - All - Selector type: string selector: description: |- selector is required, and only meaningful, when from is Selector: a standard label selector over Namespace objects. properties: matchExpressions: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: description: |- A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. properties: key: description: key is the label key that the selector applies to. type: string operator: description: |- operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: description: |- values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. items: type: string type: array x-kubernetes-list-type: atomic required: - key - operator type: object type: array x-kubernetes-list-type: atomic matchLabels: additionalProperties: type: string description: |- matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object x-kubernetes-map-type: atomic type: object type: object database: description: |- DatabaseSpec is the Postgres connection this TerdutServer uses. Exactly one of dsn or postgresClusterRef must be set (DESIGN.md §8) — this operator provisions no database either way, only wires up one that exists. properties: dsn: description: |- dsn is a DSN with no password in it, e.g. "postgres://terdut@terdut-postgres:5432/terdut?sslmode=require" -- mutually exclusive with postgresClusterRef. type: string passwordSecretRef: description: |- passwordSecretRef is where PGPASSWORD comes from for the dsn path. pgx falls back to libpq's environment variables for anything the DSN omits, so the password never appears in the DSN string itself. Unused on the postgresClusterRef path -- the Zalando-generated Secret is wired in directly instead. properties: key: description: key is the data key inside the Secret holding the raw value. minLength: 1 type: string name: description: name is the Secret's name. minLength: 1 type: string required: - key - name type: object postgresClusterRef: description: |- postgresClusterRef names a Zalando postgres-operator CR instead of a plain DSN -- mutually exclusive with dsn. properties: name: minLength: 1 type: string required: - name type: object type: object x-kubernetes-validations: - message: exactly one of dsn or postgresClusterRef must be set rule: '(has(self.dsn) ? 1 : 0) + (has(self.postgresClusterRef) ? 1 : 0) == 1' deadman: description: |- DeadmanSpec controls dead man's switch alerts. Matchers/Timeout/Severity map straight to TERDUT_DEADMAN_MATCHERS/TERDUT_DEADMAN_TIMEOUT/ TERDUT_DEADMAN_SEVERITY. properties: matchers: type: string severity: type: string timeout: type: string type: object image: description: ImageSpec is the terdut-server image to run. properties: repository: minLength: 1 type: string tag: minLength: 1 type: string required: - repository - tag type: object networking: description: |- NetworkingSpec is how this TerdutServer is reached from outside the cluster. hostname/gatewayListener describe the intended Gateway API HTTPRoute (matching charts/terdut-server's own templates/httpproxy.yaml, despite its name — that chart carries a Gateway API HTTPRoute, not a Contour HTTPProxy), but creating that HTTPRoute isn't implemented yet: it needs the Gateway API types as a new dependency, and nothing about proving a TerdutServer boots and bootstraps a real server depends on external ingress existing. Tracked as a near-term follow-up, not deferred to a later ROADMAP.md stage the way Deployment/database/bootstrap once were. properties: gatewayListener: description: |- gatewayListener is the HTTPRoute's sectionName once it exists. Empty attaches to every matching listener, including plaintext HTTP. type: string hostname: description: hostname the HTTPRoute will carry once it exists. type: string servicePort: default: 8080 description: |- servicePort is both the Service's port and the HTTPRoute's backend port once it exists. Defaults to 8080, matching the chart's own service.port default. format: int32 type: integer type: object notify: description: |- NotifySpec controls push notifications via ntfy. Empty ntfyURL disables notifications entirely (matches the chart's own default). properties: fallbackTopic: type: string ntfyURL: type: string repeatEvery: type: string tokenSecretRef: description: |- tokenSecretRef is an optional bearer token for an access-controlled ntfy. Leave unset for an open ntfy. properties: key: description: key is the data key inside the Secret holding the raw value. minLength: 1 type: string name: description: name is the Secret's name. minLength: 1 type: string required: - key - name type: object type: object oidc: description: |- OIDCSpec controls single sign-on. Fields the chart also exposes but DESIGN.md's spec doesn't (usernameClaim, emailClaim, groupsClaim, trustEmail) use terdut-server's own defaults (preferred_username/email/groups/false) rather than being added here speculatively. properties: adminGroup: type: string allowedGroups: items: type: string type: array clientID: type: string clientSecretRef: description: |- SecretKeyRef names one data key inside a Secret. Every use of this type in TerdutServerSpec resolves in the TerdutServer's own namespace (it's wired straight into the Deployment's pod spec as a secretKeyRef env source, which Kubernetes itself only allows same-namespace) -- unlike the generated credentials Secret (DESIGN.md §6), which always lives in the operator's own namespace and is never referenced through this type. properties: key: description: key is the data key inside the Secret holding the raw value. minLength: 1 type: string name: description: name is the Secret's name. minLength: 1 type: string required: - key - name type: object enabled: type: boolean issuer: type: string name: default: SSO type: string scopes: default: openid profile email type: string sessionMaxAge: default: 12h type: string type: object passwordLogin: default: true description: |- passwordLogin: whether a user may sign in, or sign up, with a password. type: boolean replicas: default: 1 description: |- replicas. terdut-server is not horizontally-scale-tested; keep this at its default of 1 unless you've verified otherwise -- the sweeper and the notifier are unsynchronised singletons. format: int32 type: integer sweeper: description: |- SweeperSpec controls incident auto-resolve/archive timing. Values are Go duration strings (e.g. "6h"), passed straight through to the TERDUT_STALE_AFTER/TERDUT_ARCHIVE_AFTER env vars exactly as written -- not a structured metav1.Duration, since terdut-server parses them itself and a round-trip through a different type would buy nothing. properties: archiveAfter: type: string staleAfter: type: string type: object required: - database - image - networking type: object status: description: status defines the observed state of TerdutServer properties: conditions: description: conditions represent the current state of the TerdutServer resource. items: description: Condition contains details for one aspect of the current state of this API Resource. properties: lastTransitionTime: description: |- 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 type: string message: description: |- message is a human readable message indicating details about the transition. This may be an empty string. maxLength: 32768 type: string observedGeneration: description: |- 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 type: integer reason: description: |- 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. maxLength: 1024 minLength: 1 pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ type: string status: description: status of the condition, one of True, False, Unknown. enum: - "True" - "False" - Unknown type: string type: description: type of condition in CamelCase or in foo.example.com/CamelCase. maxLength: 316 pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string required: - lastTransitionTime - message - reason - status - type type: object type: array x-kubernetes-list-map-keys: - type x-kubernetes-list-type: map credentialsSecretRef: description: |- credentialsSecretRef is the generated instance-scoped credential (DESIGN.md §6) -- pure output, always in the operator's own namespace, under a fixed data key ("token"). Set only once Bootstrapped is True. properties: key: description: key is the data key inside the Secret holding the raw value. minLength: 1 type: string name: description: name is the Secret's name. minLength: 1 type: string required: - key - name type: object observedGeneration: description: |- observedGeneration is the .metadata.generation this status was last computed against — the standard way a client (or `kubectl wait`) tells "applied" from "seen" (DESIGN.md §7). format: int64 type: integer serviceName: description: |- serviceName is the Service this controller created for the Deployment, so other objects can reference it without recomputing the naming convention. type: string type: object required: - spec type: object served: true storage: true subresources: status: {}