Documentation
¶
Overview ¶
pkg/doctor/compose.go
Reads docker-compose.yaml and extracts service definitions. Classifies services as stateless (Deployments) or stateful (Motif candidates).
Index ¶
- Constants
- Variables
- func AugmentWithComposeService(info *orktypes.ProjectInfo, svc ComposeService, composeDir string)
- func BuildNotificationSecret(envMap map[string]string) string
- func ClusterReachable() bool
- func CurrentContext() string
- func DeduplicateKatalogGVKs(path string) error
- func Detect(dir string) (*orktypes.ProjectInfo, error)
- func DetectComposeFile(dir string) string
- func DetectLicense(dir string) string
- func DockerfileTemplate(l orktypes.Language) string
- func EnsureDependencies() error
- func EnsureIngressController() error
- func EnsureKindCluster(name string) error
- func EnsureMetricsServer() error
- func FetchRuntimeLogs() (tail string, err error)
- func GenerateBundle(name, namespace string, secrets, config []orktypes.EnvVar, outputDir string) error
- func GetEnvValue(vars []orktypes.EnvVar, key string) (string, bool)
- func GlobalKomposerPath() (string, error)
- func GoInstalled() bool
- func HasSMTP(vars []orktypes.EnvVar) bool
- func HasSlack(vars []orktypes.EnvVar) bool
- func HelmAvailable() bool
- func ImageTag(registry, appName, tag string) string
- func Init(info *orktypes.ProjectInfo, opts GenerateOptions) error
- func InstallOrUpgradeOrkestra(version, values string, upgrade bool) error
- func KatalogChanged(dir string) bool
- func KubectlAvailable() bool
- func NotificationEnvVars(vars []orktypes.EnvVar) map[string]string
- func OrkestraInstalled() bool
- func OrkestraInstalledRunning() bool
- func ParseEnvFile(path string) ([]orktypes.EnvVar, error)
- func ReadCRName(appYAML string) (string, error)
- func RestartOrkestra() error
- func SplitEnvVars(vars []orktypes.EnvVar) (secrets, config []orktypes.EnvVar)
- func StateDir() (string, error)
- func StatefulDepsPerApp(cf *ComposeFile, appNames []string, stateful []StatefulService) map[string][]StatefulService
- type ComposeFile
- type ComposeService
- type DeployState
- type GenerateOptions
- type GitAuthor
- type GlobalKomposer
- type IngressController
- type KnownMotif
- type KomposerMeta
- type KomposerSources
- type ProjectState
- type RuntimeStatus
- type StatefulService
Constants ¶
const ( BundleFile = "bundle.yaml" AppSecretFile = "app-secrets.yaml" AppConfigFile = "app-config.yaml" ApplicationFile = "app.yaml" Orkestra = "orkestra" OrkestraRuntime = "orkestra-runtime" OrkestraNamespace = "orkestra-system" OrkestraChartRepo = "https://orkspace.github.io/orkestra" OrkestraChartName = "orkestra" // Tunnelling OrkestraControlCenter = "orkestra-cc" OrkestraControlCenterPort = "8081" )
const ( NotificationSecretName = "orkestra-notification" NotificationSecretFile = "orkestra-notification-secret.yaml" )
const (
// KindClusterName is the default kind cluster created by `ork deploy --dev`.
KindClusterName = "orkestra-playground"
)
const (
RuntimeKatalogPath = "__runtime_katalog_do_not_edit.yml"
)
Variables ¶
var ComposeFileVariants = []string{
"docker-compose.yaml",
"docker-compose.yml",
"compose.yaml",
"compose.yml",
}
ComposeFileVariants stores common docker compose variants
Functions ¶
func AugmentWithComposeService ¶
func AugmentWithComposeService(info *orktypes.ProjectInfo, svc ComposeService, composeDir string)
AugmentWithComposeService overlays compose-derived port and env vars onto info.
Port: if the service declares ports:, the container port (right-hand side of the mapping) replaces info.Port — it is more authoritative than the .env PORT or language default because it reflects the actual published container port.
Env vars: only replaced when the service has env_file: or environment: entries. The resolved set merges root .env → env_file → environment: in priority order (see resolveServiceEnvVars). If neither source is present, info.EnvVars is left as-is so that vars detected by Detect() are preserved.
composeDir should be the directory containing the docker-compose.yaml file; all relative env_file paths are resolved against it.
func BuildNotificationSecret ¶
BuildNotificationSecret generates the orkestra-notification Kubernetes Secret YAML. When applied to orkestra-system and referenced by runtime.extraEnvFrom, it injects SMTP/Slack credentials into the Orkestra runtime so pkg/konfig can pick them up as normal env vars.
func ClusterReachable ¶
func ClusterReachable() bool
ClusterReachable reports whether kubectl can reach the cluster configured in the current kubeconfig (KUBECONFIG env, ~/.kube/config, or --kubeconfig flag resolved by root.go). Times out after 5 seconds.
func CurrentContext ¶
func CurrentContext() string
CurrentContext returns the active kubectl context name.
func DeduplicateKatalogGVKs ¶
DeduplicateKatalogGVKs reads the merged katalog at path, collapses all CRDs that share the same GVK into one, and writes the result back.
When ork kompose merges multiple single-app katalogs, each produces a CRD with apiTypes.kind: ConfigMap. Orkestra forbids duplicate GVKs at runtime, so this must be called before ork generate bundle in the multi-app flow.
Merge strategy for each duplicate-GVK group:
- operatorBox lifecycle hooks (onCreate, onReconcile, …): list fields concatenated
- labelSelector: union of all key-value pairs (first value wins on collision)
- allowedNamespaces: union of all namespace strings
- status: kept from the first (canonical) CRD — all duplicates are identical
func Detect ¶
func Detect(dir string) (*orktypes.ProjectInfo, error)
Detect scans a project directory and returns a populated ProjectInfo describing everything ork doctor can infer about the application.
Detection includes:
- Dockerfile / Containerfile presence
- Git commit (short SHA)
- Primary programming language and marker file
- .env parsing, including config vs secret variables
- SMTP/Slack environment variable hints
- Application port (from .env or language defaults)
- Frontend detection via static dirs or JS frameworks
- License detection from common license files
- docker-compose.yaml discovery
Missing .env files are not treated as errors. The function returns an error only when parsing .env fails or when filesystem access is not possible.
func DetectComposeFile ¶
DetectComposeFile looks for docker-compose.yaml in dir and returns the path. Returns empty string when no compose file is found.
func DetectLicense ¶
DetectLicense scans the project directory for common license files (LICENSE, LICENSE.txt, LICENSE.md, COPYING, etc). It returns a normalized SPDX-style license name based on the first line of the file. If no license file is found or cannot be read, an empty string is returned.
func DockerfileTemplate ¶
DockerfileTemplate returns a starter Dockerfile snippet for the detected language. If the language is unknown, it returns an empty string.
func EnsureDependencies ¶
func EnsureDependencies() error
EnsureDependencies installs kubectl and helm if they are missing. Uses a spinner for each installation step.
func EnsureIngressController ¶ added in v0.4.0
func EnsureIngressController() error
EnsureIngressController installs nginx-ingress if no ingress controller is found on the current cluster. Uses the kind-specific manifest when the current context is a kind cluster; otherwise installs via Helm.
func EnsureKindCluster ¶
EnsureKindCluster creates a kind cluster named `name` if it does not already exist, then switches kubectl to its context. Downloads the kind binary from GitHub releases if not found in PATH or ~/.orkestra/bin — Go is not required.
func EnsureMetricsServer ¶ added in v0.4.0
func EnsureMetricsServer() error
EnsureMetricsServer ensures the Kubernetes metrics-server is installed.
It checks for the metrics-server deployment using `kubectl get -o json` for unambiguous detection via exit status. If not present, it attempts installation via Helm, using a kind-specific flag when needed.
Any failure (check or install) is treated as non-fatal: the error is logged and the user is instructed to install metrics-server manually.
func FetchRuntimeLogs ¶
FetchRuntimeLogs saves the last 100 log lines from the Orkestra runtime to /tmp/orkestra/runtime.log. If the control-center deployment exists but has no ready replicas, its logs are also saved to /tmp/orkestra/controlcenter.log. Returns the last 10 lines of the runtime log for inline display.
func GenerateBundle ¶
func GenerateBundle(name, namespace string, secrets, config []orktypes.EnvVar, outputDir string) error
GenerateBundle writes the app Secret and ConfigMap YAML files into outputDir. The caller is responsible for creating outputDir before calling.
func GetEnvValue ¶
GetEnvValue returns the value of an ENV var or false if not exists
func GlobalKomposerPath ¶
GlobalKomposerPath returns ~/.orkestra/deploy/komposer.yaml.
func GoInstalled ¶
func GoInstalled() bool
GoInstalled reports whether the Go toolchain is present in PATH. Required when kind needs to be installed via `go install`.
func HelmAvailable ¶
func HelmAvailable() bool
HelmAvailable reports whether helm is present in PATH.
func ImageTag ¶
ImageTag returns the full image reference for a build. tag defaults to the git commit short SHA when empty.
func Init ¶
func Init(info *orktypes.ProjectInfo, opts GenerateOptions) error
Init generates .orkestra/katalog.yaml and .orkestra/app.yaml, creates the .orkestra/ directory, and updates .gitignore to exclude the bundle directory.
func KatalogChanged ¶
KatalogChanged returns true when .orkestra/katalog.yaml has uncommitted changes or was modified by the most recent commit. Either condition means the operator should be restarted after the bundle is applied so it picks up the new configuration.
func KubectlAvailable ¶
func KubectlAvailable() bool
KubectlAvailable reports whether kubectl is present in PATH.
func NotificationEnvVars ¶
NotificationEnvVars maps developer .env keys to Orkestra konfig env var names. Only keys with non-empty values are included.
func OrkestraInstalled ¶
func OrkestraInstalled() bool
OrkestraInstalled reports whether the Orkestra runtime deployment exists and is available in the given namespace.
func OrkestraInstalledRunning ¶
func OrkestraInstalledRunning() bool
OrkestraInstalled reports whether the Orkestra runtime deployment exists and is available and running in the given namespace.
func ParseEnvFile ¶
ParseEnvFile reads a .env file and returns all non-blank, non-comment lines. Variables tagged with "# ork:cfg" on the same line have IsCfg = true; all others are treated as secrets.
func ReadCRName ¶
ReadCRName reads the ConfigMap name from .orkestra/app.yaml. Returns the name (e.g. "my-app-orkestra") so callers don't need to re-derive it.
func RestartOrkestra ¶
func RestartOrkestra() error
RestartOrkestra issues a rollout restart of the runtime deployment and waits up to 3 minutes for it to become available again.
func SplitEnvVars ¶
SplitEnvVars partitions parsed variables into secrets and config vars.
func StatefulDepsPerApp ¶
func StatefulDepsPerApp(cf *ComposeFile, appNames []string, stateful []StatefulService) map[string][]StatefulService
StatefulDepsPerApp maps each buildable app name to the stateful services whose Motif declaration belongs in that app's katalog.
Each stateful service is declared exactly once — in the katalog of the first app (in appNames order) that lists it in depends_on. If no app declares a depends_on relationship with a given stateful service, it is assigned to appNames[0] as a fallback so it still gets deployed exactly once.
Example: three apps all depend on postgres and two depend on redis. Result: postgres and redis each appear in one katalog only (the earliest app in appNames that depends on each), not repeated across every depending app.
Types ¶
type ComposeFile ¶
type ComposeFile struct {
Services map[string]ComposeService `yaml:"services"`
}
ComposeFile is the parsed docker-compose.yaml.
func ParseCompose ¶
func ParseCompose(path string) (*ComposeFile, error)
ParseCompose reads and parses a docker-compose.yaml file.
type ComposeService ¶
type ComposeService struct {
Image interface{} `yaml:"image,omitempty"` // string
Build interface{} `yaml:"build,omitempty"` // string or object
Ports interface{} `yaml:"ports,omitempty"` // []string or []int
Environment interface{} `yaml:"environment,omitempty"`
EnvFile interface{} `yaml:"env_file,omitempty"` // string or []string or [{path,required}]
Volumes interface{} `yaml:"volumes,omitempty"`
DependsOn interface{} `yaml:"depends_on,omitempty"`
}
ComposeService is one service entry in a docker compose file.
func (ComposeService) BuildContext ¶
func (s ComposeService) BuildContext() (context, dockerfile string)
BuildContext extracts the build context directory and optional Dockerfile path from the service's build: field. Returns ("", "") when build: is not set.
String form: build: ./app → context="./app", dockerfile="" Map form: build: {context: ./app, dockerfile: ./Dockerfile.prod}
func (ComposeService) ContainerPort ¶
func (s ComposeService) ContainerPort() string
ContainerPort returns the container (right-hand) port from the first ports: entry. Handles all compose port formats:
- "8080" → "8080"
- "3001:3000" → "3000"
- "127.0.0.1:8000:8080" → "8080"
- integer 8080 → "8080"
- long form {target: 8080} → "8080"
func (ComposeService) DependsOnNames ¶
func (s ComposeService) DependsOnNames() []string
DependsOnNames returns the service names this service depends on. Handles both the list form (depends_on: [a, b]) and the map/condition form (depends_on: {a: {condition: service_healthy}}).
func (ComposeService) EnvFileList ¶
func (s ComposeService) EnvFileList() []string
EnvFileList returns the env_file paths declared on this service. Handles string, []string, and long form [{path: "...", required: false}].
type DeployState ¶
type DeployState struct {
ClusterContext string `json:"clusterContext"`
Projects map[string]*ProjectState `json:"projects"`
}
DeployState is the contents of ~/.orkestra/deploy/state.json.
func LoadState ¶
func LoadState() (*DeployState, error)
LoadState reads the state file. Returns an empty state if not found.
func (*DeployState) PreviousImage ¶
func (s *DeployState) PreviousImage(appName string) string
PreviousImage returns the image deployed before the last deploy, or "" if none.
func (*DeployState) RecordDeploy ¶
func (s *DeployState) RecordDeploy(appName, namespace, katalogPath, newImage string)
RecordDeploy captures the current image as previous before recording the new one. Call this BEFORE patching the cluster so previousImage is always the live image.
func (*DeployState) Save ¶
func (s *DeployState) Save() error
Save writes the state file atomically.
type GenerateOptions ¶
type GenerateOptions struct {
NoHA bool // skip HPA and PDB; single replica
NoSecure bool // skip deletionProtection and protection labels
Clean bool // add cleanupOnShutdown: true to deletionProtection
Name string // override app name
AddIngress bool // force-include Ingress even when no frontend was detected
NotifyMe bool // add notification block
UseCompose string // path to docker-compose.yaml (expand stateful services via Motifs)
OutDir string // override .orkestra/ directory; empty = info.Dir/.orkestra
// InjectStateful, when non-nil, specifies exactly which stateful services
// to inject into this app's katalog and app.yaml. When set it takes
// precedence over the UseCompose-based auto-detection, allowing the caller
// to supply a pre-filtered, per-app slice derived from depends_on analysis.
// Use nil (not an empty slice) to fall back to UseCompose detection.
InjectStateful []StatefulService
// StatefulDeps lists stateful services (Motifs) this app must wait for
// before its Deployment is created. Emits when: conditions in onCreate.
StatefulDeps []StatefulService
// StatelessDeps lists sibling app names this app must wait for before
// its Deployment is created. Emits when: conditions in onCreate.
StatelessDeps []string
}
GenerateOptions controls which sections are included in the generated Katalog.
type GitAuthor ¶
func LastCommitAuthor ¶
LastCommitAuthor returns "Name <email>" from the most recent Git commit.
type GlobalKomposer ¶
type GlobalKomposer struct {
APIVersion string `yaml:"apiVersion"`
Kind string `yaml:"kind"`
Metadata KomposerMeta `yaml:"metadata"`
Imports KomposerSources `yaml:"imports"`
}
GlobalKomposer is the structure of ~/.orkestra/deploy/komposer.yaml. It aggregates Katalog paths from all deployed projects on this machine.
func LoadGlobalKomposer ¶
func LoadGlobalKomposer() (*GlobalKomposer, error)
LoadGlobalKomposer reads the global Komposer, returning a fresh one if absent.
func (*GlobalKomposer) DeployedProjects ¶
func (k *GlobalKomposer) DeployedProjects() []string
DeployedProjects returns app names inferred from the Komposer source paths. Paths are expected to contain a .orkestra/ directory segment.
func (*GlobalKomposer) RegisterKatalog ¶
func (k *GlobalKomposer) RegisterKatalog(katalogPath string) bool
RegisterKatalog adds katalogPath to the Komposer sources if not already present. Returns true when the path was newly added.
func (*GlobalKomposer) Save ¶
func (k *GlobalKomposer) Save() error
Save writes the global Komposer file.
type IngressController ¶
type IngressController string
IngressController is the ingress controller detected on the cluster.
const ( IngressNginx IngressController = "nginx" IngressTraefik IngressController = "traefik" IngressNone IngressController = "" )
type KnownMotif ¶
type KnownMotif struct {
Image string // detected image prefix (may include registry like confluentinc/)
MotifRef string // short name in orkestra-motifs
AppYAMLKeys []string // keys to add to app.yaml
AdminUI string // companion admin UI name
}
KnownMotif maps a detected infrastructure image to its Motif reference.
type KomposerMeta ¶
type KomposerSources ¶
type KomposerSources struct {
Files []string `yaml:"files,omitempty"`
}
type ProjectState ¶
type ProjectState struct {
Name string `json:"name"`
Namespace string `json:"namespace"`
CurrentImage string `json:"currentImage"`
PreviousImage string `json:"previousImage,omitempty"`
KatalogPath string `json:"katalogPath"`
DeployedAt time.Time `json:"deployedAt"`
}
ProjectState tracks one deployed project.
type RuntimeStatus ¶
RuntimeStatus is the result of CheckRuntimeHealth.
func CheckRuntimeHealth ¶
func CheckRuntimeHealth() RuntimeStatus
CheckRuntimeHealth waits up to healthCheckTimeout for the Orkestra runtime deployment to have at least one ready replica. It polls every 2 seconds. If pods are in CrashLoopBackOff, it returns immediately with the reason.
type StatefulService ¶
type StatefulService struct {
Name string
Motif KnownMotif
Image string
}
StatefulService describes a detected infrastructure service.
func ClassifyServices ¶
func ClassifyServices(cf *ComposeFile) (stateless []string, stateful []StatefulService)
ClassifyServices separates compose services into stateless (Deployments) and stateful (Motif-backed) based on known infrastructure images.