blob: ad70e41ca840395dbb6128e48e7b2289454b3ff8 [file] [log] [blame] [view] [edit]
# SDK/Chroot Interactions Reference
This file contains more in depth information about interacting with the SDK
(a.k.a. chroot) in the Build API.
[The SDK tutorial](../tutorials/5_hello_chroot.md) provides a quick
walk-through of the steps to set up an endpoint that runs inside the SDK,
and is the recommended starting point if you're just getting started.
## Chroot Assert Options
Where an endpoint is run is determined by the Chroot Assert Service and Method
Options.
See the [Build API Proto Reference](./build_api_proto.md) for more information.
## Overview: The "Path" Messages
The "Path" messages generally refers to three different messages that are used
to inject and extract artifacts; `Path`, `ResultPath`, and `SyncedDir`.
All three messages can be found in
[common.proto](chromium.googlesource.com/chromiumos/infra/proto/+/refs/heads/main/src/chromiumos/common.proto).
## The `Path` and `ResultPath` Messages
At its core, `Path` message simply represents a path on the filesystem inside
or outside of the SDK.
The message has a `path` string field for the path itself, which should
generally be an absolute path.
It also has a `location` field to note whether the path is inside or outside
of the SDK.
When constructing a request the `location` will virtually always be outside,
and when constructing a response the `location` will virtually always be inside.
There are plans to make `location` optional in the long term except in very
specific edge cases, but it is currently required.
The `ResultPath` message is simply a named wrapper around a `Path` message to
allow easily identifying it when used.
There may be at most one `ResultPath` message per request.
A `ResultPath` message in a response is essentially meaningless.
A `ResultPath` field never needs to be used directly in an endpoint, it is only
for the Build API itself; instead, the endpoint can produce (or simply locate)
the files however is most convenient and put those paths in the response, and
they will still end up in the final result path.
There are two use cases for these messages.
Files/directories in `Path` messages in a request are automatically injected
into the SDK.
Files/directories in `Path` messages in a response are automatically extracted
from the SDK when there is a `ResultPath` message in the request.
### Artifact Injection
Injection is accomplished by simply setting a `Path` message in a request to
the **file or directory** that is to be injected.
The files/directories are copied into a `/tmp` directory in the SDK.
Each `Path` gets a separate `/tmp` directory to avoid collisions.
When given a directory, the contents will be copied recursively.
This injection process is handled entirely by the Build API itself.
The endpoint itself will only ever see the injected path, and does not need to
worry about the outside path, or cleaning up the file.
#### Injection Examples
The following examples provide the populated request values outside the SDK,
as well as the request values inside the SDK, which is what the endpoint would
actually see.
**Example 1**: Single file.
* Request Outside: Request from outside the SDK used to invoke the Build API.
* `Path` = ~/input/file.txt
* Request Inside: Generated request inside the SDK the endpoint actually sees.
* `Path` = /tmp/tmp-abc123/file.txt
**Example 2**: Single directory.
* Request Outside
* `Path` = ~/input
* ~/input
* file.txt
* subdir/other-file.txt
* Request Inside
* `Path` = /tmp/tmp-abc123
* /tmp/tmp-abc123
* file.txt
* subdir/other-file.txt
**Example 3**: Multiple paths.
* Request Outside
* `Path` = ~/input
* ~/input
* file.txt
* subdir/other-file.txt
* `Path` = ~/file1.txt
* `Path` = ~/file2.txt
* Request Inside
* `Path` = /tmp/tmp-abc123
* /tmp/tmp-abc123
* file.txt
* subdir/other-file.txt
* `Path` = /tmp/tmp-xyz789/file1.txt
* `Path` = /tmp/tmp-123456/file2.txt
### Artifact Extraction
The two components to extraction are a `ResultPath` field in the request, and
one or more `Path` fields in the response.
The `ResultPath` specifies the path outside the SDK where the artifact(s) should
be extracted to.
The `Path` fields specify one or more files and/or directories inside the SDK
that should be extracted.
The artifacts inside the SDK do not need to be collected prior to extraction,
however, **non-unique names will cause undefined behavior**.
In practice, that currently means files will be overwritten, and directories
will raise an error.
The behavior of non-unique names may change at any time, and in the future
we may define the behavior as something other than what it is today, so until
such a time, ensure you have unique paths to guarantee it works properly.
See examples 5 and 6 for possible collision outputs today.
**Example 1**: Multiple unique files.
* Request
* `ResultPath` = ~/results
* Response
* `Path` file1 = /inside/file1
* `Path` file2 = /other/inside/file2
* Result:
* ~/results
* file1
* file2
**Example 2**: Multiple directories.
* Request
* `ResultPath` = ~/results
* Response
* `Path` dir1 = /inside/dir1
* /inside/dir1
* file1
* file2
* `Path` dir2 = /other/inside/dir2
* /other/inside/dir2
* foo
* bar
* Result:
* ~/results
* file1
* file2
* foo
* bar
**Example 3**: Nested directories.
* Request
* `ResultPath` = ~/results
* Response
* `Path` dir1 = /inside/dir
* /inside/dir
* nested1/
* file1
* nested2/
* file2
* `Path` dir2 = /other/inside/dir
* /other/inside/dir
* nested3/
* foo
* bar
* Result:
* ~/results
* nested1/
* file1
* nested2/
* file2
* nested3/
* foo
* bar
**Example 4**: File and directory.
* Request
* `ResultPath` = ~/results
* Response
* `Path` file = /inside/file
* `Path` dir = /inside/dir
* /inside/dir
* file
* foo
* Result:
* ~/results
* file
* dir
* file
* foo
**Example 5**: (Undefined Behavior) File name collision!
* Request
* `ResultPath` = ~/results
* Response
* `Path` file1 = /inside/file = 'File content!'
* `Path` file2 = /other/inside/file = 'Different content!'
* Result:
* ~/results
* file = 'Different content!'
* Note: 'File content!' is also possible.
**Example 6**: (Undefined Behavior) File collisions in nested directories.
* Request
* `ResultPath` = ~/results
* Response
* `Path` dir1 = /inside/dir1
* /inside/dir1
* nested/
* file = "Dir1 File!"
* `Path` dir2 = /other/inside/dir2
* /other/inside/dir2
* nested/
* file = "Dir2 File!"
* Result:
* Error: nested exists.
* Return code: 1
## `SyncedDir` Message
A `SyncedDir` must be in a request to use the functionality.
The `SyncedDir` provides a means of syncing the contents of a directory into
and out of the SDK.
Everything inside the directory in injected into the SDK just like a directory
in a `Path` field would be.
The key difference is that the contents of the directory are also extracted
from the SDK after the endpoint completes.
This is a destructive operation, it will remove files that were in the directory
if they were deleted from the folder inside the SDK.
### Example
* Request Outside
* `SyncedDir` = ~/synced
* ~/synced
* foo.txt
* subdir/bar.txt
* Request Inside Before Execution
* `SyncedDir` = /tmp/tmp-abc123
* /tmp/tmp-abc123
* foo.txt
* subdir/bar.txt
* Request Inside After Execution
* `SyncedDir` = /tmp/tmp-abc123
* /tmp/tmp-abc123
* foo.txt
* new-file.txt
* subdir/replaced-bar.txt
* Final Directory Contents
* ~/synced
* foo.txt
* new-file.txt
* subdir/replaced-bar.txt