Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ostree-layers and ostree-overrride-layers #1830

Closed
wants to merge 3 commits into from
Closed
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
8 changes: 8 additions & 0 deletions docs/manual/treefile.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,14 @@ It supports the following parameters:
* `packages-$basearch`: Array of strings, optional: Set of installed packages, used
only if $basearch matches the target architecture name.

* `ostree-layers`: Array of strings, optional: After all packages are unpacked,
check out these OSTree refs, which must already be in the destination repository.
Any conflicts with packages will be an error.

* `ostree-override-layers`: Array of strings, optional: Like above, but any
files present in packages and prior layers will be silently overriden.
This is useful for development builds to replace parts of the base tree.

* `bootstrap_packages`: Array of strings, optional: Deprecated; you should
now just include this set in the main `packages` array.

Expand Down
43 changes: 43 additions & 0 deletions rust/src/treefile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,8 @@ fn treefile_merge(dest: &mut TreeComposeConfig, src: &mut TreeComposeConfig) {
merge_vecs!(
repos,
packages,
ostree_layers,
ostree_override_layers,
install_langs,
initramfs_args,
units,
Expand Down Expand Up @@ -593,6 +595,12 @@ struct TreeComposeConfig {
// Deprecated option
#[serde(skip_serializing_if = "Option::is_none")]
bootstrap_packages: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "ostree-layers")]
ostree_layers: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "ostree-override-layers")]
ostree_override_layers: Option<Vec<String>>,

// Content installation opts
#[serde(skip_serializing_if = "Option::is_none")]
Expand Down Expand Up @@ -994,6 +1002,7 @@ packages:
mod ffi {
use super::*;
use glib_sys;
use glib::translate::*;
use libc;
use std::io::Seek;
use std::os::unix::io::{AsRawFd, RawFd};
Expand Down Expand Up @@ -1077,6 +1086,40 @@ mod ffi {
ref_from_raw_ptr(tf).serialized.as_ptr()
}

#[no_mangle]
pub extern "C" fn ror_treefile_get_ostree_layers(tf: *mut Treefile) -> *mut *mut libc::c_char {
let tf = ref_from_raw_ptr(tf);
if let Some(ref layers) = tf.parsed.ostree_layers {
layers.to_glib_full()
} else {
ptr::null_mut()
}
}

#[no_mangle]
pub extern "C" fn ror_treefile_get_ostree_override_layers(tf: *mut Treefile) -> *mut *mut libc::c_char {
let tf = ref_from_raw_ptr(tf);
if let Some(ref layers) = tf.parsed.ostree_override_layers {
layers.to_glib_full()
} else {
ptr::null_mut()
}
}

#[no_mangle]
pub extern "C" fn ror_treefile_get_all_ostree_layers(tf: *mut Treefile) -> *mut *mut libc::c_char {
let tf = ref_from_raw_ptr(tf);
let mut ret : Vec<String> = Vec::new();
if let Some(ref layers) = tf.parsed.ostree_layers {
ret.extend(layers.iter().cloned())
}
if let Some(ref layers) = tf.parsed.ostree_override_layers {
ret.extend(layers.iter().cloned())
}
ret.to_glib_full()
}


#[no_mangle]
pub extern "C" fn ror_treefile_get_rojig_spec_path(tf: *mut Treefile) -> *const libc::c_char {
let tf = ref_from_raw_ptr(tf);
Expand Down
1 change: 1 addition & 0 deletions src/app/rpmostree-compose-builtin-rojig.c
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ install_packages (RpmOstreeRojigCompose *self,

g_autofree char *ret_new_inputhash = NULL;
if (!rpmostree_composeutil_checksum (dnf_context_get_goal (dnfctx),
self->repo,
self->treefile_rs, self->treefile,
&ret_new_inputhash, error))
return FALSE;
Expand Down
24 changes: 23 additions & 1 deletion src/app/rpmostree-compose-builtin-tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@

#include "libglnx.h"

static gboolean
pull_local_into_target_repo (OstreeRepo *src_repo,
OstreeRepo *dest_repo,
const char *checksum,
GCancellable *cancellable,
GError **error);

static char *opt_workdir;
static gboolean opt_workdir_tmpfs;
static char *opt_cachedir;
Expand Down Expand Up @@ -344,7 +351,7 @@ install_packages (RpmOstreeTreeComposeContext *self,

/* FIXME - just do a depsolve here before we compute download requirements */
g_autofree char *ret_new_inputhash = NULL;
if (!rpmostree_composeutil_checksum (dnf_context_get_goal (dnfctx),
if (!rpmostree_composeutil_checksum (dnf_context_get_goal (dnfctx), self->repo,
self->treefile_rs, self->treefile,
&ret_new_inputhash, error))
return FALSE;
Expand Down Expand Up @@ -707,6 +714,21 @@ rpm_ostree_compose_context_new (const char *treefile_pathstr,
error))
return FALSE;

cgwalters marked this conversation as resolved.
Show resolved Hide resolved
g_auto(GStrv) layers = ror_treefile_get_all_ostree_layers (self->treefile_rs);
if (layers && *layers && !opt_unified_core)
return glnx_throw (error, "ostree-layers requires unified-core mode");

if (self->build_repo != self->repo)
{
for (char **iter = layers; iter && *iter; iter++)
{
const char *layer = *iter;
if (!pull_local_into_target_repo (self->repo, self->build_repo, layer,
cancellable, error))
return FALSE;
}
}

self->treefile_rootval = json_parser_get_root (self->treefile_parser);
if (!JSON_NODE_HOLDS_OBJECT (self->treefile_rootval))
return glnx_throw (error, "Treefile root is not an object");
Expand Down
19 changes: 19 additions & 0 deletions src/app/rpmostree-composeutil.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@

gboolean
rpmostree_composeutil_checksum (HyGoal goal,
OstreeRepo *repo,
RORTreefile *tf,
JsonObject *treefile,
char **out_checksum,
Expand Down Expand Up @@ -92,6 +93,24 @@ rpmostree_composeutil_checksum (HyGoal goal,
if (!rpmostree_dnf_add_checksum_goal (checksum, goal, NULL, error))
return FALSE;

if (tf)
{
GLNX_AUTO_PREFIX_ERROR ("Resolving ostree-layers", error);
g_auto(GStrv) layers = ror_treefile_get_all_ostree_layers (tf);
for (char **iter = layers; iter && *iter; iter++)
{
const char *layer = *iter;
g_autofree char *rev = NULL;
if (!ostree_repo_resolve_rev (repo, layer, FALSE, &rev, error))
return FALSE;
g_autoptr(GVariant) commit = NULL;
if (!ostree_repo_load_commit (repo, rev, &commit, NULL, error))
return FALSE;
const char *content_checksum = ostree_commit_get_content_checksum (commit);
g_checksum_update (checksum, (const guint8*) content_checksum, strlen (content_checksum));
}
}

*out_checksum = g_strdup (g_checksum_get_string (checksum));
return TRUE;
}
Expand Down
1 change: 1 addition & 0 deletions src/app/rpmostree-composeutil.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ G_BEGIN_DECLS

gboolean
rpmostree_composeutil_checksum (HyGoal goal,
OstreeRepo *repo,
RORTreefile *tf,
JsonObject *treefile,
char **out_checksum,
Expand Down
79 changes: 79 additions & 0 deletions src/libpriv/rpmostree-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -3758,6 +3758,81 @@ rpmostree_context_get_kernel_changed (RpmOstreeContext *self)
return self->kernel_changed;
}

static gboolean
process_one_ostree_layer (RpmOstreeContext *self,
int rootfs_dfd,
const char *ref,
OstreeRepoCheckoutOverwriteMode ovw_mode,
GCancellable *cancellable,
GError **error)
{
OstreeRepo *repo = self->ostreerepo;
OstreeRepoCheckoutAtOptions opts = { OSTREE_REPO_CHECKOUT_MODE_USER,
ovw_mode };

/* We want the checkout to match the repo type so that we get hardlinks. */
if (ostree_repo_get_mode (repo) == OSTREE_REPO_MODE_BARE)
opts.mode = OSTREE_REPO_CHECKOUT_MODE_NONE;

/* Explicitly don't provide a devino cache here. We can't do it reliably because
* of SELinux. The ostree layering infrastructure doesn't have the relabeling
* that we do for the pkgcache repo because we can't assume that we can mutate
* the input commits right now.
* opts.devino_to_csum_cache = self->devino_cache;
*/
/* Always want hardlinks */
opts.no_copy_fallback = TRUE;

g_autofree char *rev = NULL;
if (!ostree_repo_resolve_rev (repo, ref, FALSE, &rev, error))
return FALSE;

return ostree_repo_checkout_at (repo, &opts, rootfs_dfd, ".",
rev, cancellable, error);
}

static gboolean
process_ostree_layers (RpmOstreeContext *self,
int rootfs_dfd,
GCancellable *cancellable,
GError **error)
{
if (!self->treefile_rs)
return TRUE;

g_auto(GStrv) layers = ror_treefile_get_ostree_layers (self->treefile_rs);
g_auto(GStrv) override_layers = ror_treefile_get_ostree_override_layers (self->treefile_rs);
const size_t n = (layers ? g_strv_length (layers) : 0) + (override_layers ? g_strv_length (override_layers) : 0);
if (n == 0)
return TRUE;

g_auto(RpmOstreeProgress) checkout_progress = { 0, };
rpmostree_output_progress_nitems_begin (&checkout_progress, n, "Checking out ostree layers");
size_t i = 0;
for (char **iter = layers; iter && *iter; iter++)
{
const char *ref = *iter;
if (!process_one_ostree_layer (self, rootfs_dfd, ref,
OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_IDENTICAL,
cancellable, error))
return FALSE;
i++;
rpmostree_output_progress_n_items (i);
}
for (char **iter = override_layers; iter && *iter; iter++)
{
const char *ref = *iter;
if (!process_one_ostree_layer (self, rootfs_dfd, ref,
OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES,
cancellable, error))
return FALSE;
i++;
rpmostree_output_progress_n_items (i);
}
rpmostree_output_progress_end (&checkout_progress);
return TRUE;
}

gboolean
rpmostree_context_assemble (RpmOstreeContext *self,
GCancellable *cancellable,
Expand Down Expand Up @@ -4209,6 +4284,10 @@ rpmostree_context_assemble (RpmOstreeContext *self,
}
}

/* Any ostree refs to overlay */
if (!process_ostree_layers (self, tmprootfs_dfd, cancellable, error))
return FALSE;

{
cgwalters marked this conversation as resolved.
Show resolved Hide resolved
g_auto(RpmOstreeProgress) task = { 0, };
rpmostree_output_task_begin (&task, "Running posttrans scripts");
Expand Down
36 changes: 36 additions & 0 deletions tests/compose-tests/test-misc-tweaks.sh
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,35 @@ postprocess:
set -xeuo pipefail
test -f /usr/share/included-postprocess-test
EOF

for x in $(seq 3); do
rm tmp/usr -rf
mkdir -p tmp/usr/{bin,share}
mkdir tmp/usr/share/testsubdir-${x}
echo sometest${x} > tmp/usr/bin/sometestbinary-${x}
chmod a+x tmp/usr/bin/sometestbinary-${x}
echo sometestdata${x} > tmp/usr/share/sometestdata-${x}
echo sometestdata-subdir-${x} > tmp/usr/share/testsubdir-${x}/test
ostree --repo="${repobuild}" commit --consume --no-xattrs --owner-uid=0 --owner-gid=0 -b testlayer-${x} --tree=dir=tmp
done
rm tmp/usr -rf
mkdir -p tmp/usr/{share/info,bin}
echo sweet new ls binary > tmp/usr/bin/ls
ostree --repo="${repobuild}" commit --consume --no-xattrs --owner-uid=0 --owner-gid=0 -b testoverride-1 --tree=dir=tmp
cat >> ${new_treefile} <<EOF
ostree-layers:
- testlayer-1
- testlayer-2
- testlayer-3
ostree-override-layers:
- testoverride-1
EOF

export treefile=${new_treefile}


# Do the compose
compose_base_argv="${compose_base_argv} --unified-core"
runcompose
echo "ok compose"

Expand Down Expand Up @@ -113,6 +138,17 @@ assert_file_has_content_literal pkglist.txt 'systemd-'
assert_not_file_has_content pkglist.txt 'systemd-bootchart'
echo "ok recommends"

# Test overlays/overrides
for x in $(seq 3); do
ostree --repo=${repobuild} cat ${treeref} /usr/bin/sometestbinary-${x} > t
assert_file_has_content t "sometest${x}"
ostree --repo=${repobuild} cat ${treeref} /usr/share/testsubdir-${x}/test > t
assert_file_has_content t sometestdata-subdir-${x}
done
ostree --repo=${repobuild} cat ${treeref} /usr/bin/ls > ls.txt
assert_file_has_content ls.txt '^sweet new ls binary$'
echo "ok layers"

# Check that add-files with bad paths are rejected
prepare_compose_test "add-files-failure"
pysetjsonmember "add-files" '[["foo.txt", "/var/lib/foo.txt"]]'
Expand Down