Documentation
¶
Overview ¶
Package v1alpha1 defines the CLI-facing configuration kinds for the Educates v4 installer. The API group is cli.educates.dev/v1alpha1.
These kinds are translated by the CLI into the operator chart values plus the four platform CRs (EducatesClusterConfig, SecretsManager, LookupService, SessionManager). They are NOT applied to the cluster directly.
Index ¶
- Constants
- Variables
- func SchemaURL(kind string) string
- type ACMEConfig
- type AWSConfig
- type ApiServerConfig
- type ClusterNode
- type ClusterNodeTaint
- type Config
- type EducatesConfig
- type EducatesConfigTarget
- type EducatesEKSConfig
- type EducatesGKEConfig
- type EducatesInlineConfig
- type EducatesLocalConfig
- type GCPConfig
- type ImageVersion
- type InlineImageRegistry
- type InlinePolicyEnforcement
- type LocalClusterConfig
- type LocalIngressConfig
- type LocalOperatorConfig
- type LocalResolverConfig
- type LocalSecretPropagationConfig
- type LocalWebsiteStylingConfig
- type NetworkingConfig
- type OperatorImage
- type RegistryMirror
- type ThemeDataRef
- type TypeMeta
- type VolumeMount
Constants ¶
const ( GroupName = "cli.educates.dev" Version = "v1alpha1" APIVersion = GroupName + "/" + Version KindEducatesLocalConfig = "EducatesLocalConfig" // SchemaBaseURL is where the release workflow publishes the JSON // schemas (GitHub Pages, mapped to schemas.educates.dev upstream). // Matches the $id baked into each schema file. SchemaBaseURL = "https://schemas.educates.dev/cli/" + Version + "/" )
const KindEducatesConfig = "EducatesConfig"
const KindEducatesEKSConfig = "EducatesEKSConfig"
const KindEducatesGKEConfig = "EducatesGKEConfig"
const KindEducatesInlineConfig = "EducatesInlineConfig"
Variables ¶
var LocalDevImageNames = []string{
"session-manager",
"training-portal",
"base-environment",
"docker-registry",
"pause-container",
"secrets-manager",
"tunnel-manager",
"image-cache",
"assets-server",
"lookup-service",
"node-ca-injector",
}
LocalDevImageNames is the set of platform images a dev-built CLI defaults to its compiled-in registry — exactly the images the root Makefile's `build-core-images` produces. Workshop language images (jdk*, conda) are deliberately excluded: their chart defaults point at published images that exist, so optional-workshop flows keep working in a dev cluster; a developer who builds them locally adds explicit imageVersions entries, which always win.
Functions ¶
Types ¶
type ACMEConfig ¶
type ACMEConfig struct {
// Email is the contact address registered with the ACME server.
// Required.
Email string `yaml:"email"`
// Server is the ACME directory URL. Empty defers to the CRD
// default (Let's Encrypt production).
Server string `yaml:"server,omitempty"`
}
ACMEConfig is the user-controllable ACME surface — email + optional server override. The solver provider (CloudDNS for GKE, Route53 for EKS) is an invariant of the kind, not user-controlled here.
type AWSConfig ¶
type AWSConfig struct {
// AccountId is the 12-digit AWS account that owns the Route53 zone
// and the IRSA IAM roles. Required.
AccountId string `yaml:"accountId"`
// Region is the AWS region. Required (Route53 hosted-zone API
// calls and ACME-DNS01 challenges go through this region).
Region string `yaml:"region"`
// Route53HostedZoneId names the Route53 hosted zone for the
// wildcard domain. Required.
Route53HostedZoneId string `yaml:"route53HostedZoneId"`
// CertManagerRoleARN is the IAM role assumed by the cert-manager
// K8s ServiceAccount via IRSA. Empty defaults to
// arn:aws:iam::<accountId>:role/educates-cert-manager.
CertManagerRoleARN string `yaml:"certManagerRoleARN,omitempty"`
// ExternalDNSRoleARN is the IAM role assumed by the external-dns
// K8s ServiceAccount via IRSA. Empty defaults to
// arn:aws:iam::<accountId>:role/educates-external-dns.
ExternalDNSRoleARN string `yaml:"externalDNSRoleARN,omitempty"`
}
AWSConfig is the AWS envelope for EducatesEKSConfig.
type ApiServerConfig ¶
type ClusterNode ¶
type ClusterNode struct {
Role string `yaml:"role"`
Labels map[string]string `yaml:"labels,omitempty"`
Taints []ClusterNodeTaint `yaml:"taints,omitempty"`
}
ClusterNode describes a node of the local kind cluster. Leaving cluster.nodes empty keeps the default single-control-plane cluster; when set, the list fully declares the cluster's nodes and must include a control-plane. Labels become Kubernetes node labels; taints are registered on the node at join time (worker nodes).
type ClusterNodeTaint ¶
type ClusterNodeTaint struct {
Key string `yaml:"key"`
Value string `yaml:"value,omitempty"`
Effect string `yaml:"effect"`
}
ClusterNodeTaint is a Kubernetes node taint applied to a worker node when it registers. Value is optional; Effect is one of NoSchedule, PreferNoSchedule, or NoExecute.
type Config ¶
Config is the marker interface implemented by every CLI config kind in this API group. Loaders return Config; callers type-switch to the concrete kind they care about.
type EducatesConfig ¶
type EducatesConfig struct {
TypeMeta `yaml:",inline"`
// Target carries CLI-side-effect inputs (kind cluster bootstrap +
// macOS resolver). Optional; when absent the CLI just applies the
// declared CRs with no side effects. provider drives which side
// effects run.
Target *EducatesConfigTarget `yaml:"target,omitempty"`
// Operator chart values surface — same fields as on every scenario kind.
Operator LocalOperatorConfig `yaml:"operator,omitempty"`
// CR-spec passthrough sections. Untyped on purpose: the JSON schema
// (generated from the CRDs) is the source of truth for field shape.
// Omitted LookupService means it is not deployed.
EducatesClusterConfig map[string]interface{} `yaml:"educatesClusterConfig,omitempty"`
SecretsManager map[string]interface{} `yaml:"secretsManager,omitempty"`
LookupService map[string]interface{} `yaml:"lookupService,omitempty"`
SessionManager map[string]interface{} `yaml:"sessionManager,omitempty"`
}
EducatesConfig is the escape-hatch CLI config kind. Its body mirrors the four platform CRDs verbatim (layout B1: section keys = camelCase CRD kind, body = CR .spec). The CLI wraps apiVersion/kind/metadata.name at translate time and applies the result without further transformation.
Per the locked design:
- No CLI-inferred defaults (no host-IP nip.io, no auto-injected TLS).
- No invariants. Every CRD field is settable.
- Static CRD defaults still apply at apply-time via apiserver defaulting.
The CR-spec sections are passed through as untyped maps; the schema (not Go types) is the source of truth for their shape.
type EducatesConfigTarget ¶
type EducatesConfigTarget struct {
Provider string `yaml:"provider,omitempty"`
Cluster LocalClusterConfig `yaml:"cluster,omitempty"`
Resolver LocalResolverConfig `yaml:"resolver,omitempty"`
}
EducatesConfigTarget carries CLI-side-effect inputs. cluster/resolver reuse the same Go types as EducatesLocalConfig so the kind cluster + macOS resolver code paths can accept either kind interchangeably.
type EducatesEKSConfig ¶
type EducatesEKSConfig struct {
TypeMeta `yaml:",inline"`
// AWS carries the account + Route53 + IAM role configuration.
// accountId, region, and route53HostedZoneId are required; both IRSA
// role ARNs default from accountId when empty.
AWS AWSConfig `yaml:"aws"`
// Domain is the wildcard ingress subdomain. Required.
Domain string `yaml:"domain"`
// ACME carries the cert-manager ACME config. Required: email.
// (Shared shape with EducatesGKEConfig.)
ACME ACMEConfig `yaml:"acme"`
// ExternalTLSTermination asserts that TLS for the ingress domain is
// terminated outside the cluster (cloud load balancer or proxy
// forwarding plain HTTP inward). Generated portal and workshop URLs
// use https regardless of in-cluster certificate presence. Maps to
// SessionManager.spec.ingressOverrides.protocol: https.
ExternalTLSTermination bool `yaml:"externalTLSTermination,omitempty"`
// Top-level toggles shared with EducatesLocalConfig. Defaults:
// clusterAdmin=false, lookupService=true, imagePrePuller=true.
ClusterAdmin *bool `yaml:"clusterAdmin,omitempty"`
LookupService *bool `yaml:"lookupService,omitempty"`
ImagePrePuller *bool `yaml:"imagePrePuller,omitempty"`
WebsiteStyling LocalWebsiteStylingConfig `yaml:"websiteStyling,omitempty"`
SecretPropagation LocalSecretPropagationConfig `yaml:"secretPropagation,omitempty"`
ImageVersions []ImageVersion `yaml:"imageVersions,omitempty"`
Operator LocalOperatorConfig `yaml:"operator,omitempty"`
}
EducatesEKSConfig is the EKS production scenario kind. All cluster services are operator-installed and authenticated via IRSA (IAM Roles for Service Accounts) — no static credentials anywhere.
Locked invariants applied by TranslateEKS:
- mode: Managed
- ingress.ingressClassName: contour
- ingress.controller.provider: BundledContour bundledContour.envoyServiceType: LoadBalancer
- ingress.certificates.provider: BundledCertManager
- ingress.certificates.bundledCertManager.issuerType: ACME acme.solvers.dns01.provider: Route53
- dns.provider: BundledExternalDNS bundledExternalDNS.provider: Route53
- policyEnforcement: BundledKyverno (cluster + workshop)
func (*EducatesEKSConfig) ApplyCLIDefaults ¶
func (c *EducatesEKSConfig) ApplyCLIDefaults(projectVersion, imageRepository string) *EducatesEKSConfig
func (*EducatesEKSConfig) WithDefaults ¶
func (c *EducatesEKSConfig) WithDefaults() *EducatesEKSConfig
type EducatesGKEConfig ¶
type EducatesGKEConfig struct {
TypeMeta `yaml:",inline"`
// GCP carries the project + service-account configuration. project
// is required; both WI service-account emails default from project
// when empty.
GCP GCPConfig `yaml:"gcp"`
// Domain is the wildcard ingress subdomain. Required.
Domain string `yaml:"domain"`
// ACME carries the cert-manager ACME config. email is required;
// server defaults to Let's Encrypt production at CRD level.
ACME ACMEConfig `yaml:"acme"`
// ExternalTLSTermination asserts that TLS for the ingress domain is
// terminated outside the cluster (cloud load balancer or proxy
// forwarding plain HTTP inward). Generated portal and workshop URLs
// use https regardless of in-cluster certificate presence. Maps to
// SessionManager.spec.ingressOverrides.protocol: https.
ExternalTLSTermination bool `yaml:"externalTLSTermination,omitempty"`
// Top-level toggles shared with EducatesLocalConfig. Defaults per
// the locked design: clusterAdmin=false, lookupService=true,
// imagePrePuller=true.
ClusterAdmin *bool `yaml:"clusterAdmin,omitempty"`
LookupService *bool `yaml:"lookupService,omitempty"`
ImagePrePuller *bool `yaml:"imagePrePuller,omitempty"`
WebsiteStyling LocalWebsiteStylingConfig `yaml:"websiteStyling,omitempty"`
SecretPropagation LocalSecretPropagationConfig `yaml:"secretPropagation,omitempty"`
ImageVersions []ImageVersion `yaml:"imageVersions,omitempty"`
Operator LocalOperatorConfig `yaml:"operator,omitempty"`
}
EducatesGKEConfig is the GKE production scenario kind. All cluster services are operator-installed and authenticated via Workload Identity — no static credentials anywhere.
Locked invariants applied by TranslateGKE:
- mode: Managed
- ingress.ingressClassName: contour
- ingress.controller.provider: BundledContour bundledContour.envoyServiceType: LoadBalancer
- ingress.certificates.provider: BundledCertManager
- ingress.certificates.bundledCertManager.issuerType: ACME acme.solvers.dns01.provider: CloudDNS
- dns.provider: BundledExternalDNS bundledExternalDNS.provider: CloudDNS
- policyEnforcement: BundledKyverno (cluster + workshop)
User-provided fields are narrow on purpose. Power users who need non-WI auth, alternate Contour envoyServiceType, or different policy engines drop to the EducatesConfig escape hatch.
func (*EducatesGKEConfig) ApplyCLIDefaults ¶
func (c *EducatesGKEConfig) ApplyCLIDefaults(projectVersion, imageRepository string) *EducatesGKEConfig
ApplyCLIDefaults mirrors EducatesLocalConfig's CLI-binary defaulting.
func (*EducatesGKEConfig) WithDefaults ¶
func (c *EducatesGKEConfig) WithDefaults() *EducatesGKEConfig
WithDefaults applies static + project-derived defaults.
type EducatesInlineConfig ¶
type EducatesInlineConfig struct {
TypeMeta `yaml:",inline"`
// Domain is the wildcard ingress subdomain. Required.
Domain string `yaml:"domain"`
// IngressClassName names the IngressClass routing to the BYO
// controller (e.g. "contour", "openshift-default"). Required.
IngressClassName string `yaml:"ingressClassName"`
// WildcardCertificateSecret names a kubernetes.io/tls Secret in the
// operator namespace with keys tls.crt + tls.key, valid for
// *.<Domain>. Required unless externalTLSTermination is set, in which
// case TLS lives outside the cluster and no in-cluster certificate is
// referenced.
WildcardCertificateSecret string `yaml:"wildcardCertificateSecret,omitempty"`
// CACertificateSecret optionally names a Secret with the ca.crt
// key for the CA chain that issued the wildcard. Workshops mount it
// when they need to trust outbound calls to private endpoints.
CACertificateSecret string `yaml:"caCertificateSecret,omitempty"`
// ClusterIssuerName is informational — when a cert-manager
// ClusterIssuer signed the wildcard, this name surfaces in status.
// Optional.
ClusterIssuerName string `yaml:"clusterIssuerName,omitempty"`
// ImageRegistry optionally rewrites workshop image refs to live
// behind an in-cluster mirror and supplies pull credentials.
ImageRegistry InlineImageRegistry `yaml:"imageRegistry,omitempty"`
// PolicyEnforcement names the engines the cluster already enforces.
// Defaults: clusterEngine=Kyverno, workshopEngine=Kyverno.
PolicyEnforcement InlinePolicyEnforcement `yaml:"policyEnforcement,omitempty"`
// ExternalTLSTermination asserts that TLS for the ingress domain is
// terminated outside the cluster (corporate load balancer or proxy
// forwarding plain HTTP inward). No in-cluster wildcard certificate
// is referenced, and generated portal and workshop URLs use https.
// Maps to EducatesClusterConfig.spec.inline.ingress.protocol: https
// with no wildcardCertificateSecretRef.
ExternalTLSTermination bool `yaml:"externalTLSTermination,omitempty"`
// Top-level toggles shared with EducatesLocalConfig.
ClusterAdmin *bool `yaml:"clusterAdmin,omitempty"`
LookupService *bool `yaml:"lookupService,omitempty"`
ImagePrePuller *bool `yaml:"imagePrePuller,omitempty"`
WebsiteStyling LocalWebsiteStylingConfig `yaml:"websiteStyling,omitempty"`
SecretPropagation LocalSecretPropagationConfig `yaml:"secretPropagation,omitempty"`
ImageVersions []ImageVersion `yaml:"imageVersions,omitempty"`
Operator LocalOperatorConfig `yaml:"operator,omitempty"`
}
EducatesInlineConfig is the BYO scenario kind. The user asserts that cert-manager (or a wildcard cert), an ingress controller, and a policy engine already exist on the cluster, and Educates uses them via EducatesClusterConfig.spec.inline references.
Locked invariants applied by TranslateInline:
- EducatesClusterConfig.spec.mode: Inline
- All values flow under spec.inline; spec.{ingress,dns, policyEnforcement,imageRegistry} stay unset (forbidden by CEL on the CRD).
No target.provider: Inline mode is provider-agnostic by design. EducatesInlineConfig is accepted by render and deploy but not by 'local cluster create' (which is kind-only).
func (*EducatesInlineConfig) ApplyCLIDefaults ¶
func (c *EducatesInlineConfig) ApplyCLIDefaults(projectVersion, imageRepository string) *EducatesInlineConfig
ApplyCLIDefaults mirrors EducatesLocalConfig's CLI-binary defaulting for operator.image.
func (*EducatesInlineConfig) WithDefaults ¶
func (c *EducatesInlineConfig) WithDefaults() *EducatesInlineConfig
WithDefaults applies static defaults that are independent of host environment. Operator.logLevel mirrors EducatesLocalConfig. Policy engines default to Kyverno (matches CRD kubebuilder defaults).
type EducatesLocalConfig ¶
type EducatesLocalConfig struct {
TypeMeta `yaml:",inline"`
Cluster LocalClusterConfig `yaml:"cluster,omitempty"`
Resolver LocalResolverConfig `yaml:"resolver,omitempty"`
Ingress LocalIngressConfig `yaml:"ingress,omitempty"`
ClusterAdmin *bool `yaml:"clusterAdmin,omitempty"`
LookupService *bool `yaml:"lookupService,omitempty"`
ImagePrePuller *bool `yaml:"imagePrePuller,omitempty"`
WebsiteStyling LocalWebsiteStylingConfig `yaml:"websiteStyling,omitempty"`
SecretPropagation LocalSecretPropagationConfig `yaml:"secretPropagation,omitempty"`
ImageVersions []ImageVersion `yaml:"imageVersions,omitempty"`
Operator LocalOperatorConfig `yaml:"operator,omitempty"`
}
EducatesLocalConfig is the laptop-kind-cluster scenario kind. Empty file (apiVersion + kind only) is valid; defaults fill in everything else.
Hard exclusions (escalate to EducatesConfig escape hatch): mode, target.provider, dns, ACME, imageRegistry.prefix, cluster-service discriminators, analytics, dockerDaemon.*, storage.*, network.blockCIDRs, workshops.frameAncestors, debug.
func (*EducatesLocalConfig) ApplyCLIDefaults ¶
func (c *EducatesLocalConfig) ApplyCLIDefaults(projectVersion, imageRepository string) *EducatesLocalConfig
ApplyCLIDefaults fills in image defaults from the CLI binary's compiled-in version/registry. Deterministic per CLI binary; the output is reproducible as long as the same CLI version is used.
All binaries: operator.image.{repository,tag} default to `<imageRepository>/educates-operator` : projectVersion (matching `installer/charts/educates-installer/values.yaml`).
Developer binaries only (non-semver version, e.g. `latest` from `make`): every LocalDevImageNames entry the user didn't override is defaulted to `<imageRepository>/educates-<name>:<projectVersion>`, so a locally built image set deploys with zero manual config. Release binaries (semver-stamped) skip this entirely and behave as before. User-supplied imageVersions entries always win.
func (*EducatesLocalConfig) WithDefaults ¶
func (c *EducatesLocalConfig) WithDefaults() *EducatesLocalConfig
Static defaults — independent of host environment. Applied after YAML unmarshal, before validation.
Two further layers of defaulting are applied by callers (typically the command code, not the loader):
- ApplyCLIDefaults uses the CLI binary's compiled-in version/registry to fill operator.image.{repository,tag} when empty. Deterministic per CLI binary, so safe for GitOps.
- ApplyHostDefaults uses the laptop's host IP to fill ingress.domain with a nip.io fallback. Host-specific, NOT safe for GitOps; only applied when the user opted into laptop-convenience mode (`--local-config`).
type GCPConfig ¶
type GCPConfig struct {
// Project is the GCP project that owns the CloudDNS zone and the
// Workload Identity service accounts. Required.
Project string `yaml:"project"`
// CertManagerServiceAccount is the GCP service-account email bound
// to the cert-manager K8s ServiceAccount via Workload Identity.
// Empty defaults to cert-manager@<project>.iam.gserviceaccount.com.
CertManagerServiceAccount string `yaml:"certManagerServiceAccount,omitempty"`
// ExternalDNSServiceAccount is the GCP service-account email bound
// to the external-dns K8s ServiceAccount via Workload Identity.
// Empty defaults to external-dns@<project>.iam.gserviceaccount.com.
ExternalDNSServiceAccount string `yaml:"externalDNSServiceAccount,omitempty"`
}
GCPConfig is the GCP envelope for EducatesGKEConfig.
type ImageVersion ¶
type InlineImageRegistry ¶
type InlinePolicyEnforcement ¶
type LocalClusterConfig ¶
type LocalClusterConfig struct {
ListenAddress string `yaml:"listenAddress,omitempty"`
RegistryListenAddress string `yaml:"registryListenAddress,omitempty"`
ApiServer ApiServerConfig `yaml:"apiServer,omitempty"`
Networking NetworkingConfig `yaml:"networking,omitempty"`
VolumeMounts []VolumeMount `yaml:"volumeMounts,omitempty"`
RegistryMirrors []RegistryMirror `yaml:"registryMirrors,omitempty"`
Nodes []ClusterNode `yaml:"nodes,omitempty"`
}
type LocalIngressConfig ¶
type LocalIngressConfig struct {
Domain string `yaml:"domain,omitempty"`
// Insecure serves the local cluster over plain HTTP with no TLS. No
// CA or certificate is needed, so the one-time `educates local
// secrets add ca` step is skipped. Translates to the operator's
// certificates.provider: None with ingress.protocol: http.
Insecure bool `yaml:"insecure,omitempty"`
}
type LocalOperatorConfig ¶
type LocalOperatorConfig struct {
Image OperatorImage `yaml:"image,omitempty"`
ImagePullSecrets []string `yaml:"imagePullSecrets,omitempty"`
LogLevel string `yaml:"logLevel,omitempty"`
}
type LocalResolverConfig ¶
type LocalSecretPropagationConfig ¶
type LocalSecretPropagationConfig struct {
ImagePullSecretNames []string `yaml:"imagePullSecretNames,omitempty"`
}
type LocalWebsiteStylingConfig ¶
type LocalWebsiteStylingConfig struct {
DefaultTheme string `yaml:"defaultTheme,omitempty"`
ThemeDataRefs []ThemeDataRef `yaml:"themeDataRefs,omitempty"`
}
LocalWebsiteStylingConfig is the narrow subset exposed by EducatesLocalConfig. Full styling surface (per-page overrides, HTML snippets) is escape-hatch only.
type NetworkingConfig ¶
type OperatorImage ¶
type OperatorImage struct {
Repository string `yaml:"repository,omitempty"`
Tag string `yaml:"tag,omitempty"`
// PullPolicy maps to the chart's image.pullPolicy. Empty lets the
// chart auto-derive it (Always for floating tags like develop,
// IfNotPresent otherwise). Set to "Always" for local-registry
// development where the tag (e.g. :dev) is rebuilt under the same
// name on each push.
PullPolicy string `yaml:"pullPolicy,omitempty"`
}
type RegistryMirror ¶
type RegistryMirror struct {
Mirror string `yaml:"mirror"`
URL string `yaml:"url,omitempty"`
Username string `yaml:"username,omitempty"`
Password string `yaml:"password,omitempty"`
Port string `yaml:"port,omitempty"`
BindIP string `yaml:"bindIP,omitempty"`
}
RegistryMirror is the user-declared pull-through cache surface. The always-on localhost:5001 mirror is implicit and not represented here.
type ThemeDataRef ¶
type TypeMeta ¶
type TypeMeta struct {
APIVersion string `yaml:"apiVersion" json:"apiVersion"`
Kind string `yaml:"kind" json:"kind"`
}
TypeMeta carries the apiVersion/kind discriminator. Every CLI config kind embeds this for kind-aware loading.