Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions projects/start-os/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,9 @@ for the detail behind its highlights.
- **The OS log stays focused on actionable errors on a network whose router
advertises a route with more than one next hop.**

- **A service that mounts a dependency's files read-write fails to start when
that dependency is not installed**, naming the missing volume.

### Security

- **Service mount paths are validated and confined to their intended
Expand Down
2 changes: 2 additions & 0 deletions projects/start-sdk/docs/src/dependencies.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,8 @@ const mounts = sdk.Mounts.of().mountVolume({ volumeId: 'main', subpath: null, mo
})
```

The volume has to exist when the container starts: if the dependency is not installed, the mount fails, `main` throws, and the service shows the error alongside its dependency warning. A `subpath` that does not exist yet inside the volume is created for a read-write mount.

## Init Order

Dependencies are resolved during initialization in this order:
Expand Down
3 changes: 2 additions & 1 deletion projects/start-sdk/lib/mainFn/Mounts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,8 @@ export class Mounts<Manifest extends T.SDKManifest> {
/**
* Add a mount from a dependency package's volume. The mount is always a
* directory — StartOS does not bind a dependency's file. To reach a single
* file, mount the directory holding it.
* file, mount the directory holding it. The volume must exist when the
* container starts; a missing dependency fails the start.
*
* @param options - Dependency ID, volume ID, mountpoint, readonly flag, and optional subpath
* @returns A new Mounts instance with this dependency mount added
Expand Down
6 changes: 6 additions & 0 deletions shared-libs/crates/start-core/locales/i18n.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2567,6 +2567,12 @@ service.effects.dependency.unknown-dependency-kind:
es_ES: "tipo de dependencia desconocido %{kind}"
fr_FR: "type de dépendance inconnu %{kind}"
pl_PL: "nieznany rodzaj zależności %{kind}"
service.effects.dependency.volume-missing:
en_US: "volume %{volume} of %{package} does not exist — is %{package} installed?"
de_DE: "Volume %{volume} von %{package} existiert nicht — ist %{package} installiert?"
es_ES: "el volumen %{volume} de %{package} no existe — ¿está instalado %{package}?"
fr_FR: "le volume %{volume} de %{package} n'existe pas — %{package} est-il installé ?"
pl_PL: "wolumin %{volume} pakietu %{package} nie istnieje — czy %{package} jest zainstalowany?"

# service/service_actor.rs
service.service-actor.error-synchronizing-state:
Expand Down
20 changes: 15 additions & 5 deletions shared-libs/crates/start-core/src/service/effects/dependency.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,11 +174,21 @@ pub async fn mount(
}: MountParams,
) -> Result<(), Error> {
let context = context.deref()?;
let source = confined_join(
&data_dir(DATA_DIR, &package_id, &volume_id),
subpath.as_deref().unwrap_or(Path::new("")),
)
.await?;
let volume = data_dir(DATA_DIR, &package_id, &volume_id);
if tokio::fs::metadata(&volume).await.is_err() {
return Err(Error::new(
eyre!(
"{}",
t!(
"service.effects.dependency.volume-missing",
package = package_id,
volume = volume_id
)
),
ErrorKind::NotFound,
));
}
let source = confined_join(&volume, subpath.as_deref().unwrap_or(Path::new(""))).await?;
let rootfs = context
.seed
.persistent_container
Expand Down
Loading