Documentation
¶
Overview ¶
Package compose parses a Docker Compose file into Levelrail's own desired-state model, in two shapes depending on the caller. The direct-import path (ToDesiredServices, via Validate) is deliberately narrow: every service needs a pre-built image (no build:), since there is no build context to build one from (a pasted file, no git checkout). The git-sourced expand path (ExpandBuildService, via ValidateForBuild) allows build: for exactly that reason: it always has a real checkout. Both paths share the same narrow scope otherwise: environment/ports/volumes accept both Compose's short and long forms (see yaml.go), but only the fields Levelrail's own model has room for: no port ranges, no tmpfs/npipe mounts. A UDP port is published straight on the host, never through the HTTP proxy. restart: and networks: both parse and are surfaced as non-blocking Notices instead of being silently dropped or translated: see Notices for why neither has a real translation onto how Levelrail runs a service. depends_on: parses into spec.Service.DependsOn / store. DesiredService.DependsOn and IS enforced: internal/reconcile/ application.Controller waits for a dependency's container to start before creating this service's own, real Docker Compose's own default depends_on semantic (service_started, not service_healthy). command: and entrypoint: both parse and translate into store.DesiredService's own Command and Entrypoint fields. volumes: additionally accepts an absolute host path on the left side as a bind mount (ValidateForBuild rejects one; see that method's own doc comment for why), gated at the HTTP layer to AbilityRoot and, even then, against internal/bindmount's own forbidden-path list (see validateBindMountHostPath).
Index ¶
- Constants
- func CheckDeclaredVars(data []byte, file string, lim StrictLimits, env map[string]string) error
- func ExpandBuildService(svc spec.Service, sourceDir string, opts ...ExpandOption) (services map[string]spec.Service, warnings []string, err error)
- func FromDesiredServices(appName string, services []store.DesiredService) (string, error)
- func GenerateValue(kind string, length int) (string, error)
- func InterpolateDeclared(value string, env map[string]string) (string, error)
- func MaxShmBytes() int64
- func MemberAppName(app, service string) string
- func RedactSecretContent(body []byte) ([]byte, bool, error)
- func ScanSecretLiterals(data []byte, file string, lim StrictLimits, match SecretMatcher) error
- func ServiceHostViolations(h HostAccess, hostPaths []string) []string
- func ServiceKeyOf(app, member string) (string, bool)
- func SupportedServiceKeys() []string
- func ToDesiredServices(appName string, f *File) (services []store.DesiredService, warnings []string, err error)
- type Command
- type DependsOn
- type Deploy
- type Device
- type EnvFileRef
- type Environment
- type ExpandOption
- type File
- type Healthcheck
- type HostAccess
- type MagicVar
- type MissingVar
- type Networks
- type Notice
- type NoticeLevel
- type Port
- type SecretMatcher
- type Service
- type StrictError
- type StrictErrors
- type StrictLimits
- type Translation
- type UnresolvedVar
- type UnsupportedKey
- type Volume
Constants ¶
const ( DependsOnConditionStarted = "service_started" DependsOnConditionHealthy = "service_healthy" DependsOnConditionCompleted = "service_completed_successfully" )
Depends_on conditions from the long form.
const ( CodeStrictTooLarge = "compose_too_large" CodeStrictUnsupportedKey = "compose_unsupported_key" CodeStrictRejected = "compose_rejected" CodeStrictSecretLiteral = "compose_secret_literal" CodeStrictVarMissing = "compose_var_missing" )
Stable refusal codes for referenced compose files. The IaC layer maps them onto its own code list, so the strings must not change.
const PullPolicyAlways = "always"
PullPolicyAlways is pull_policy: always, the only non-default value this package supports.
const RedactedSecretMarker = "__levelrail_redacted__"
RedactedSecretMarker replaces an inline secret body in stored compose history; the real value lives only in the secrets store.
Variables ¶
This section is empty.
Functions ¶
func CheckDeclaredVars ¶
CheckDeclaredVars reports every ${VAR} in the file that env does not declare. Plan passes names with placeholder values, so no secret is read.
func ExpandBuildService ¶
func ExpandBuildService(svc spec.Service, sourceDir string, opts ...ExpandOption) (services map[string]spec.Service, warnings []string, err error)
ExpandBuildService parses the compose file at svc.Build.Path (relative to sourceDir) and returns one spec.Service per compose service, plus a warning for each healthcheck left untranslated.
func FromDesiredServices ¶ added in v0.2.0
func FromDesiredServices(appName string, services []store.DesiredService) (string, error)
FromDesiredServices builds a compose.yaml that reconstructs appName's services as closely as this package's File/Service model allows. Secret, database, and vault env values never carry over as real values, only a ${SERVICE_SECRET_<key>} placeholder (no secret value is ever captured, the whole point of this function). Domains, HostPort/BindAddress, bind mounts, resources, health checks, and egress policy are dropped too: none of those round-trips through this package's own compose model (see compose.go's doc comment).
func GenerateValue ¶
GenerateValue produces a real value for a generatable MagicVar kind. length <= 0 uses each kind's own sane default.
func InterpolateDeclared ¶
InterpolateDeclared expands ${VAR} forms in one value from env only. The host environment is never read. An unset plain ${VAR} is compose_var_missing.
func MaxShmBytes ¶
func MaxShmBytes() int64
MaxShmBytes is the largest /dev/shm any app may request, compose or API. An invalid value keeps the default: tmpfs no mem_limit bounds must stay capped.
func MemberAppName ¶
MemberAppName returns the app name that holds the env of one compose service.
func RedactSecretContent ¶
RedactSecretContent blanks every inline top-level secrets: body so a stored revision never holds plaintext. It returns the body unchanged when nothing needed redacting.
func ScanSecretLiterals ¶
func ScanSecretLiterals(data []byte, file string, lim StrictLimits, match SecretMatcher) error
ScanSecretLiterals refuses plaintext secrets in environment, labels, command, entrypoint and healthcheck values. Findings name the file, line, service and key, never the value.
func ServiceHostViolations ¶
func ServiceHostViolations(h HostAccess, hostPaths []string) []string
ServiceHostViolations reports what validate rejects for one service's host access and bind sources, for callers that cannot fully parse a file yet still must enforce the rules.
func ServiceKeyOf ¶
ServiceKeyOf reports the compose service key for a member app of app.
func SupportedServiceKeys ¶
func SupportedServiceKeys() []string
SupportedServiceKeys lists every service key the parser reads, sorted.
func ToDesiredServices ¶
func ToDesiredServices(appName string, f *File) (services []store.DesiredService, warnings []string, err error)
ToDesiredServices translates f into one store.DesiredService per compose service, named "<appName>-<serviceKey>" and linked to appName as their AppID (matching the naming convention internal/deploy's own multi-service fan-out uses). Runs Validate first, so a caller only needs to call this one function.
warnings carries one message per service whose healthcheck: could not be translated (see resolveHealthcheck), for the caller to surface.
A bind-mount volumes: entry (compose.go's own doc comment) becomes a store.ServiceBindMount, not a store.ServiceVolume: the caller must require AbilityRoot before persisting a result carrying any BindMounts, this package has no notion of a caller's abilities.
Types ¶
type Command ¶ added in v0.2.0
type Command []string
Command is command:'s and entrypoint:'s shared string-or-list union: a list passes through as exec-form args, a bare string is Compose's own shorthand for shell form, wrapped here as ["/bin/sh", "-c", "<string>"] to match Docker's own documented interpretation of a string CMD or ENTRYPOINT.
type DependsOn ¶ added in v0.2.0
type DependsOn []string
DependsOn is a service's own depends_on:'s list-or-map union, the same shape as Networks: either a plain list of service names, or a map of name to per-dependency config (condition, restart, ...) decoded down to just the names.
type Deploy ¶ added in v0.2.0
type Deploy struct {
Resources struct {
Reservations struct {
Devices []Device `yaml:"devices"`
} `yaml:"reservations"`
Limits deployLimits `yaml:"limits"`
} `yaml:"resources"`
// Replicas maps onto the same store.DesiredService.Replicas /
// spec.Service.Replicas field a service's own top-level replicas:
// (app.yaml) already resolves through. Zero means unset.
Replicas int `yaml:"replicas"`
// contains filtered or unexported fields
}
Deploy is the deploy: block; only resources.reservations.devices (GPU device reservations) and replicas are read. Every other subkey (mode, placement, update_config, rollback_config, restart_policy, endpoint_mode, labels, ...) is a Swarm-specific field with no meaning outside a Swarm cluster, so UnmarshalYAML records its presence in unsupported rather than letting it silently parse and vanish: see validateDeploy.
func (*Deploy) UnmarshalYAML ¶ added in v0.2.0
UnmarshalYAML decodes the known resources:/replicas: shapes normally, then walks the raw mapping a second time to record every other top-level key present, so validateDeploy can report exactly which Swarm-specific fields a service declared instead of a generic "deploy not supported".
type Device ¶ added in v0.2.0
type Device struct {
Driver string `yaml:"driver"`
Count yamlScalarString `yaml:"count"`
DeviceIDs []string `yaml:"device_ids"`
Capabilities []string `yaml:"capabilities"`
}
Device is one deploy.resources.reservations.devices entry.
type EnvFileRef ¶
EnvFileRef is one env_file: entry. Required is false only for the long form with required: false, where a missing file is skipped.
type Environment ¶
Environment is environment:'s string-or-list union: a KEY: VALUE map, or a list of "KEY=VALUE" strings (a bare "KEY" means "inherit from the host shell" in real Compose, decoded here as an empty value since there's no host shell to inherit from).
func (*Environment) UnmarshalYAML ¶
func (e *Environment) UnmarshalYAML(node *yaml.Node) error
UnmarshalYAML implements the map-or-list union described above.
type ExpandOption ¶
type ExpandOption func(*expandConfig)
ExpandOption configures ExpandBuildService.
func WithMagicSecrets ¶
func WithMagicSecrets(generate func(kind, key string, length int) (string, error), persist func(serviceKey, envKey, value string) error) ExpandOption
WithMagicSecrets lets ExpandBuildService resolve generated SERVICE_ variables with the same generate and persist hooks ResolveMagicVars takes. Without it, a generated variable is rejected (fail closed).
type File ¶
type File struct {
Version string
Services map[string]Service
// CapGrants lists, per service key, the cap_add values a manifest declared and
// the caller approved. Never read from YAML; unset means cap_add is rejected.
CapGrants map[string][]string
// DropUngrantedCaps drops a Review or Elevated cap_add that CapGrants no longer
// covers instead of rejecting it, for a rollback to a revision made under older policy.
DropUngrantedCaps bool
// Domains maps a service key to the real domain it should be
// reachable at, from the top-level x-levelrail-domains extension
// (Compose's own reserved x- prefix for tool-specific keys). Used
// both to set that service's own store.DesiredService.Domains (real
// ingress routing) and to resolve any ${SERVICE_FQDN_*} reference
// within that same service's environment (ResolveMagicVars).
Domains map[string]string
// RuntimeDomains holds domains assigned after deploy (service key to
// host). Only SERVICE_FQDN and SERVICE_URL resolution reads it, so a
// re-render never changes what ToDesiredServices persists.
RuntimeDomains map[string]string
// Networks lists this file's own top-level networks: names, sorted.
// Only used by Notices to detect that custom networks were declared
// at all; Levelrail doesn't create per-network isolation from this.
Networks []string
// HasSecrets/HasConfigs record whether this file declares a top-level
// secrets: or configs: block: neither has a translation onto this
// platform's own env-var/Levelrail-secrets model, so validate rejects
// either outright (unlike restart:/networks:/depends_on:, which parse
// and are merely non-blocking Notices) rather than silently dropping
// values an operator would reasonably expect to reach a container.
HasSecrets bool
HasConfigs bool
// Unsupported lists keys that parsed but are not read, so Notices can
// report them instead of dropping them silently.
Unsupported []UnsupportedKey
// InterpVars are the variables ${VAR:-default} forms in env values read
// (app env and saved env keys); nil means every variable is unset.
InterpVars map[string]string
// InterpWarnings collects names-only notes about unset variables.
InterpWarnings []string
}
File is a parsed compose.yaml.
func ParseStrict ¶
func ParseStrict(data []byte, lim StrictLimits) (*File, error)
ParseStrict parses and validates a compose file that arrived from an untrusted source (a referenced IaC attachment). On refusal the error is a StrictErrors; the non strict Parse and Validate paths are not affected.
func (*File) ApplyProfiles ¶ added in v0.2.0
ApplyProfiles drops every service whose profiles: list shares nothing with active, the same default Compose applies (a service with no profiles always runs). It returns the dropped service keys, sorted, and fails when a kept service depends on a dropped one.
func (*File) Notices ¶
Notices reports every non-blocking observation across f:
- restart: (NoticeLevelNote): an explicit "no" or "on-failure[:N]" runs the service to completion (exit 0 is done, not restarted); an unrecognized value (on-failure:abc too) is warned about and ignored.
- networks: (NoticeLevelWarning): every service in an app already shares one flat Docker network (internal/reconcile/application's NetworkName, one per app, not per compose network), so a compose file's custom networks: can't isolate services from each other here the way they would under real Compose. That's a real semantic gap for a file that expressed isolation intent, worth a warning rather than a silent drop.
- depends_on: (NoticeLevelNote): parses into DependsOn and IS enforced as start order; condition: service_healthy additionally waits for the dependency's readiness condition.
func (*File) Profiles ¶ added in v0.2.0
Profiles lists every profile name any service declares, sorted.
func (*File) ResolveEnvFiles ¶
ResolveEnvFiles reads each service's env_file: entries from inside root (composeDir is the compose file's directory relative to root) and merges them under environment:, which wins. Only a git checkout has a root, so the pasted-file path keeps the unsupported warning instead.
func (*File) Validate ¶
Validate reports every unsupported-shape problem across all services, not just the first, so a template author can fix them in one pass. Used by the direct-import path (ToDesiredServices), which has no build context (no git checkout, just a pasted file) to build a build: block from, so it rejects one outright. See ValidateForBuild for the git-sourced deploy-spec path, which does have one.
func (*File) ValidateForBuild ¶
ValidateForBuild is Validate, except a service's build: block is allowed rather than rejected: used only by the git-sourced expand-a-compose-file-into-services path (ExpandBuildService), which has a real checkout to resolve a build context against, unlike the direct-import path Validate itself still guards. Bind mounts stay rejected on this path even though Validate now allows them: the expanded result is a spec.Service (toSpecService, expand.go), and spec.Volume has no host-path concept to carry one into, so allowing one through here would either drop it silently or produce a nonsensical empty-named volume downstream.
type Healthcheck ¶
type Healthcheck struct {
Test healthcheckTest `yaml:"test"`
Interval string `yaml:"interval"`
Timeout string `yaml:"timeout"`
Retries int `yaml:"retries"`
StartPeriod string `yaml:"start_period"`
}
Healthcheck is one service's healthcheck: block, Docker Compose's own command-based health check schema (test/interval/timeout/retries/ start_period). Docker never runs it: resolveHealthcheck (healthcheck.go) translates it into this platform's own readiness probe.
type HostAccess ¶ added in v0.2.0
type HostAccess struct {
Privileged bool `yaml:"privileged"`
NetworkMode string `yaml:"network_mode"`
Pid string `yaml:"pid"`
Ipc string `yaml:"ipc"`
Uts string `yaml:"uts"`
UsernsMode string `yaml:"userns_mode"`
Cgroup string `yaml:"cgroup"`
CapAdd []string `yaml:"cap_add"`
Devices []any `yaml:"devices"`
SecurityOpt []string `yaml:"security_opt"`
VolumesFrom []string `yaml:"volumes_from"`
}
HostAccess holds the service keys that widen a container's reach into the host. None has a safe translation, so validate rejects every one that is set, citing the dockerguard rule the socket proxy would apply.
type MagicVar ¶
type MagicVar struct {
Token string
Kind string
Key string
Length int
Default string
HasDefault bool
Generatable bool
}
MagicVar is one parsed SERVICE_ placeholder found in an env value.
func FindMagicVars ¶
FindMagicVars returns every SERVICE_ token in s, in encounter order, including duplicates.
type MissingVar ¶
MissingVar is one required ${NAME:?msg} variable with no value.
func MissingRequired ¶
func MissingRequired(f *File, vars map[string]string) []MissingVar
MissingRequired lists every required variable in env values that vars does not satisfy, so a caller can report them all at once. Names and the author's message only, never values.
type Networks ¶
type Networks []string
Networks is a service's own networks:'s list-or-map union: a plain list of network names, or a map of name to per-network config (aliases, ipv4_address, ...) this decodes down to just the name, same reasoning as rawFile.Networks above.
type Notice ¶
type Notice struct {
Level NoticeLevel
Message string
// Service, Key and Alternative are set for an ignored-key warning.
Service string
Key string
Alternative string
}
Notice is one non-blocking observation about a parsed compose file.
type NoticeLevel ¶
type NoticeLevel string
NoticeLevel distinguishes a purely informational Notice from an operator-facing Warning about a semantic gap. Neither ever fails Validate: both describe compose keywords that parsed successfully but don't behave the way they would under real Docker Compose.
const ( NoticeLevelNote NoticeLevel = "note" NoticeLevelWarning NoticeLevel = "warning" )
The two NoticeLevel values Notices ever produces.
type Port ¶
type Port struct {
HostPort int
ContainerPort int
// Protocol is empty for tcp (the default) or "udp".
Protocol string
}
Port is one short-form ports: entry. ContainerPort is what store.DesiredService.Port (a single container port, not a host:container pair) actually uses.
func (*Port) UnmarshalYAML ¶
UnmarshalYAML supports both of ports:'s forms: the short scalar form ("container" or "host:container") and the long mapping form (target/published/protocol/mode keys). mode: is accepted but ignored, since Levelrail has no host-vs-ingress publishing distinction to carry it onto.
type SecretMatcher ¶
SecretMatcher reports whether a literal value under key must not live in a file. The IaC layer passes iac.LooksSecret so both guards share one detector.
type Service ¶
type Service struct {
Image string
Build *rawBuild
Environment Environment
Ports []Port
Volumes []Volume
Labels map[string]string
Networks Networks
Restart string
Healthcheck *Healthcheck
// DependsOn is depends_on:, enforced by the reconciler as a start-
// order guarantee (see this file's own doc comment and Notices).
DependsOn DependsOn
// Command overrides the image's own default CMD
// (store.DesiredService.Command), parsed from command:'s own
// string-or-list union (Command's own UnmarshalYAML in yaml.go): a
// plain string is shell-wrapped as ["/bin/sh", "-c", "<string>"],
// matching Compose's own documented behavior for that form.
Command Command
// Entrypoint overrides the image's own default ENTRYPOINT
// (store.DesiredService.Entrypoint), parsed with the same
// string-or-list union as Command.
Entrypoint Command
// User and WorkingDir are user: and working_dir:, validated like app.yaml's.
User string
WorkingDir string
// PullPolicy is pull_policy:, normalized by normalizePullPolicy into
// exactly the two states store.DesiredService.PullPolicy
// distinguishes: PullPolicyAlways forces a fresh pull even when the
// image is already present locally, empty means today's existing
// pull-if-absent behavior. Real Compose's other recognized spellings
// ("missing", "if_not_present", an unset field) all normalize to
// empty too; "never" and "build" are rejected, see
// normalizePullPolicy.
PullPolicy string
// Deploy carries the GPU device reservation and replicas count
// (gpu.go).
Deploy *Deploy
// Secrets/Configs are this service's own secrets:/configs: references
// (short string form or long {source, target,...} map form, either
// decodes fine into []any since only their presence matters here),
// the per-service counterpart to File.HasSecrets/HasConfigs; same
// rejection reasoning, see validateComposeServices.
Secrets []any
Configs []any
// Files are inline configs: content translated to container files.
Files []spec.File
// Profiles gates the service behind compose profiles (ApplyProfiles).
Profiles []string
// MemLimit and CPUs are the mem_limit: and cpus: shorthands for a hard cap.
MemLimit yamlScalarString
CPUs yamlScalarString
// ShmSize is shm_size:, the /dev/shm size Chromium based apps need.
ShmSize yamlScalarString
// Allowlisted runtime tuning keys, mapped by runtimeFromService.
Tmpfs stringList
Ulimits map[string]spec.Ulimit
Init *bool
StopGracePeriod string
ExtraHosts hostList
DNS stringList
Sysctls sysctlMap
CapDrop []string
PidsLimit int
ReadOnly bool
HostAccess HostAccess
// Strategy is x-levelrail-strategy: a deploy strategy the template needs,
// such as recreate for an app that locks its state volume. Empty means default.
Strategy string
StrategyReason string
// PlatformProbe is x-levelrail-healthcheck, see resolveServiceHealth.
PlatformProbe *spec.PlatformProbe
// PublishedTCP is x-levelrail-published-ports: tcp container ports from
// ports: published on their own host port with a private bind, instead
// of being dropped. The routed web port is the first tcp port not listed.
PublishedTCP []int
// DependsOnHealthy lists the DependsOn entries declared with
// condition: service_healthy, which wait for readiness, not just start.
DependsOnHealthy []string
// DependsOnCompleted lists the DependsOn entries declared with
// condition: service_completed_successfully, which wait for exit 0.
DependsOnCompleted []string
// EnvFiles is env_file:, read by ResolveEnvFiles when a checkout exists.
EnvFiles []EnvFileRef
}
Service is one entry under services:.
type StrictError ¶
type StrictError struct {
Code string
Rule string
Service string
Key string
Line int
Message string
}
StrictError is one refusal. Message carries names and lines only, never a value.
func (*StrictError) Error ¶
func (e *StrictError) Error() string
type StrictErrors ¶
type StrictErrors []*StrictError
StrictErrors is every refusal for one file, so an author fixes them in one pass.
func (StrictErrors) Error ¶
func (es StrictErrors) Error() string
type StrictLimits ¶
StrictLimits bounds one referenced compose file.
func LoadStrictLimits ¶
func LoadStrictLimits() StrictLimits
LoadStrictLimits reads the caps from env, falling back to the defaults on unset or invalid values.
type Translation ¶
Translation is the result of TranslateMagicVars. Generated names the secret variables that got a fresh value; the values stay in Compose only.
func TranslateMagicVars ¶
func TranslateMagicVars(src string, host func(key string) string) (Translation, error)
TranslateMagicVars rewrites Coolify SERVICE_FQDN_*, SERVICE_URL_* and generatable SERVICE_* tokens in a compose body into literal values, so the result has no placeholder left. host maps a service key to its hostname. Tokens that cannot be resolved stay untouched and are listed in Unsupported.
type UnresolvedVar ¶
UnresolvedVar is one SERVICE_ token ResolveMagicVars couldn't resolve: not a generatable kind, and no bash-style ${...:-default} fallback.
func ResolveMagicVars ¶
func ResolveMagicVars( f *File, generate func(kind, key string, length int) (string, error), persist func(serviceKey, envKey, value string) error, ) (secretEnv map[string][]string, unresolved []UnresolvedVar, err error)
ResolveMagicVars scans every service's environment and command for SERVICE_ placeholders, mutating f in place: a token with a bash-style default substitutes that default as a literal value; a generatable token (PASSWORD/USER/BASE64/HEX/REALBASE64/BASE64BYTES) found in Environment is removed from it entirely and returned via secretEnv instead, since its real value belongs in secret storage, not a literal desired-state column. Command has no equivalent secret-storage indirection (a Command entry can't be swapped for a decrypted-at-create-time secret the way an env var can), so a generatable token found there is always reported as unresolved instead, same as a default-less non-generatable token.
generate is called once per unique (kind, key) pair even when referenced by several services, so they all resolve to the same value (e.g. an app service's DB_PASSWORD and its sibling postgres service's own POSTGRES_PASSWORD both referencing SERVICE_PASSWORD_DB). persist is then called once per (service, env key) that ended up secret-backed, since secret storage is keyed per real service, not per magic-var key: the caller is expected to write that same value into whichever per-service secret store its later container-create step reads from.
A magic-var token embedded inside a larger string (not the entire env value, e.g. a composite DATABASE_URL) can still splice in a generated value: the whole assembled string is then secret-backed (persisted and added to secretEnv), the same as a whole-value generatable token, since it now contains one. A default-less, non-generatable token in that position is unresolved.
func (UnresolvedVar) String ¶
func (u UnresolvedVar) String() string
type UnsupportedKey ¶
UnsupportedKey is one compose key that parsed but has no effect here. Service is empty for a top-level key; Key is dotted for nested keys.
func (UnsupportedKey) Message ¶
func (u UnsupportedKey) Message() string
Message is the operator-facing sentence for a Notice.
type Volume ¶
type Volume struct {
Name string
HostPath string
ContainerPath string
// ReadOnly mounts read-only inside the container, from an optional
// trailing ":ro" on the short-form entry.
ReadOnly bool
}
Volume is one short-form "name:/container/path" entry, either a named Docker volume (Name set, HostPath empty) or a bind mount of a real host directory (HostPath set, Name empty): exactly one of the two is ever set, see Volume.UnmarshalYAML (yaml.go) for how the left side of the entry decides which.
func (*Volume) UnmarshalYAML ¶
UnmarshalYAML supports both of volumes:'s forms: the short scalar form ("name:/path", optionally with a trailing ":ro"/":rw") and the long mapping form (type/source/target/read_only keys). See parseVolumeShortForm and parseVolumeLongForm.