Skip to content

Commit

Permalink
WIP unified core
Browse files Browse the repository at this point in the history
  • Loading branch information
cgwalters committed Nov 14, 2017
1 parent b17af32 commit 1aa4c9d
Show file tree
Hide file tree
Showing 8 changed files with 214 additions and 86 deletions.
177 changes: 124 additions & 53 deletions src/app/rpmostree-compose-builtin-tree.c
Expand Up @@ -48,6 +48,7 @@ static gboolean opt_workdir_tmpfs;
static char *opt_cachedir;
static gboolean opt_force_nocache;
static gboolean opt_cache_only;
static gboolean opt_ex_unified_core;
static char *opt_proxy;
static char *opt_output_repodata_dir;
static char **opt_metadata_strings;
Expand All @@ -68,6 +69,7 @@ static GOptionEntry install_option_entries[] = {
{ "force-nocache", 0, 0, G_OPTION_ARG_NONE, &opt_force_nocache, "Always create a new OSTree commit, even if nothing appears to have changed", NULL },
{ "cache-only", 0, 0, G_OPTION_ARG_NONE, &opt_cache_only, "Assume cache is present, do not attempt to update it", NULL },
{ "cachedir", 0, 0, G_OPTION_ARG_STRING, &opt_cachedir, "Cached state", "CACHEDIR" },
{ "ex-unified-core", 0, 0, G_OPTION_ARG_NONE, &opt_ex_unified_core, "Use new \"unified core\" codepath", NULL },
{ "proxy", 0, 0, G_OPTION_ARG_STRING, &opt_proxy, "HTTP proxy", "PROXY" },
{ "dry-run", 0, 0, G_OPTION_ARG_NONE, &opt_dry_run, "Just print the transaction and exit", NULL },
{ "output-repodata-dir", 0, 0, G_OPTION_ARG_STRING, &opt_output_repodata_dir, "Save downloaded repodata in DIR", "DIR" },
Expand Down Expand Up @@ -101,6 +103,8 @@ typedef struct {
int rootfs_dfd;
int cachedir_dfd;
OstreeRepo *repo;
OstreeRepo *pkgcache_repo;
OstreeRepoDevInoCache *devino_cache;
char *ref;
char *previous_checksum;

Expand All @@ -126,6 +130,8 @@ rpm_ostree_tree_compose_context_free (RpmOstreeTreeComposeContext *ctx)
glnx_close_fd (&ctx->rootfs_dfd);
glnx_close_fd (&ctx->cachedir_dfd);
g_clear_object (&ctx->repo);
g_clear_object (&ctx->pkgcache_repo);
g_clear_pointer (&ctx->devino_cache, (GDestroyNotify)ostree_repo_devino_cache_unref);
g_free (ctx->ref);
g_free (ctx->previous_checksum);
g_clear_object (&ctx->treefile_parser);
Expand Down Expand Up @@ -319,16 +325,6 @@ install_packages_in_root (RpmOstreeTreeComposeContext *self,
GCancellable *cancellable,
GError **error)
{
/* TODO - uncomment this once we have SELinux working */
#if 0
g_autoptr(OstreeRepo) cache_repo =
ostree_repo_create_at (self->cachedir_dfd, "repo",
OSTREE_REPO_MODE_BARE_USER, NULL,
cancellable, error);
if (!cache_repo)
return FALSE;
#endif

DnfContext *hifctx = rpmostree_context_get_hif (self->corectx);
if (opt_proxy)
dnf_context_set_http_proxy (hifctx, opt_proxy);
Expand All @@ -347,8 +343,10 @@ install_packages_in_root (RpmOstreeTreeComposeContext *self,
GFile *contextdir = self->treefile_context_dirs->pdata[0];
dnf_context_set_repo_dir (hifctx, gs_file_get_path_cached (contextdir));

/* By default, retain packages in addition to metadata with --cachedir */
if (opt_cachedir)
/* By default, retain packages in addition to metadata with --cachedir, unless
* we're doing unified core, in which case the pkgcache repo is the cache.
*/
if (opt_cachedir && !opt_ex_unified_core)
dnf_context_set_keep_cache (hifctx, TRUE);
/* For compose, always try to refresh metadata; we're used in build servers
* where fetching should be cheap. Otherwise, if --cache-only is set, it's
Expand Down Expand Up @@ -412,6 +410,33 @@ install_packages_in_root (RpmOstreeTreeComposeContext *self,
return FALSE;
}

/* For unified core, we have a pkgcache repo. This may be auto-created under
* the workdir, or live explicitly in the dir for --cache.
*/
glnx_autofd int host_rootfs_dfd = -1;
if (opt_ex_unified_core)
{
int pkgcache_dfd = self->cachedir_dfd != -1 ? self->cachedir_dfd : self->workdir_dfd;
self->pkgcache_repo = ostree_repo_create_at (pkgcache_dfd, "pkgcache-repo",
OSTREE_REPO_MODE_BARE_USER, NULL,
cancellable, error);
if (!self->pkgcache_repo)
return FALSE;
rpmostree_context_set_repos (self->corectx, self->repo, self->pkgcache_repo);
self->devino_cache = ostree_repo_devino_cache_new ();

/* Ensure that the imported packages are labeled with *a* policy if
* possible, even if it's not the final one. This helps avoid duplicating
* all of the content.
*/
if (!glnx_opendirat (AT_FDCWD, "/", TRUE, &host_rootfs_dfd, error))
return FALSE;
g_autoptr(OstreeSePolicy) sepolicy = ostree_sepolicy_new_at (host_rootfs_dfd, cancellable, error);
if (ostree_sepolicy_get_name (sepolicy) == NULL)
return glnx_throw (error, "Unable to load SELinux policy from /");
rpmostree_context_set_sepolicy (self->corectx, sepolicy);
}

if (!rpmostree_context_prepare (self->corectx, cancellable, error))
return FALSE;

Expand Down Expand Up @@ -475,52 +500,77 @@ install_packages_in_root (RpmOstreeTreeComposeContext *self,

if (generate_from_previous)
{
if (!rpmostree_generate_passwd_from_previous (self->repo, rootfs_dfd,
const char *dest = opt_ex_unified_core ? "usr/etc/" : "etc/";
if (!rpmostree_generate_passwd_from_previous (self->repo, rootfs_dfd, dest,
treefile_dirpath,
self->previous_root, treedata,
cancellable, error))
return FALSE;
}

/* Before we install packages, drop a file to suppress the kernel.rpm dracut run.
* <https://github.com/systemd/systemd/pull/4174> */
const char *kernel_installd_path = "usr/lib/kernel/install.d";
if (!glnx_shutil_mkdir_p_at (rootfs_dfd, kernel_installd_path, 0755, cancellable, error))
return FALSE;
const char skip_kernel_install_data[] = "#!/usr/bin/sh\nexit 77\n";
const char *kernel_skip_path = glnx_strjoina (kernel_installd_path, "/00-rpmostree-skip.install");
if (!glnx_file_replace_contents_with_perms_at (rootfs_dfd, kernel_skip_path,
(guint8*)skip_kernel_install_data,
strlen (skip_kernel_install_data),
0755, 0, 0,
GLNX_FILE_REPLACE_NODATASYNC,
cancellable, error))
return FALSE;
if (opt_ex_unified_core)
{
if (!rpmostree_context_import (self->corectx, cancellable, error))
return FALSE;
if (!rpmostree_context_relabel (self->corectx, cancellable, error))
return FALSE;
rpmostree_context_set_tmprootfs_dfd (self->corectx, rootfs_dfd);
if (!rpmostree_context_assemble (self->corectx, cancellable, error))
return FALSE;

/* Now actually run through librpm to install the packages. Note this bit
* will be replaced in the future with a unified core:
* https://github.com/projectatomic/rpm-ostree/issues/729
*/
{ g_auto(GLnxConsoleRef) console = { 0, };
g_autoptr(DnfState) hifstate = dnf_state_new ();
/* Now reload the policy from the tmproot, and relabel the pkgcache - this
* is the same thing done in rpmostree_context_commit(). But here we want
* to ensure our pkgcache labels are accurate, since that will
* be important for the ostree-jigdo work.
*/
g_autoptr(OstreeSePolicy) sepolicy = ostree_sepolicy_new_at (rootfs_dfd, cancellable, error);
rpmostree_context_set_sepolicy (self->corectx, sepolicy);

guint progress_sigid = g_signal_connect (hifstate, "percentage-changed",
G_CALLBACK (on_hifstate_percentage_changed),
"Installing packages:");
if (!rpmostree_context_relabel (self->corectx, cancellable, error))
return FALSE;
}
else
{
/* The non-unified core path */

glnx_console_lock (&console);
/* Before we install packages, drop a file to suppress the kernel.rpm dracut run.
* <https://github.com/systemd/systemd/pull/4174> */
const char *kernel_installd_path = "usr/lib/kernel/install.d";
if (!glnx_shutil_mkdir_p_at (rootfs_dfd, kernel_installd_path, 0755, cancellable, error))
return FALSE;
const char skip_kernel_install_data[] = "#!/usr/bin/sh\nexit 77\n";
const char *kernel_skip_path = glnx_strjoina (kernel_installd_path, "/00-rpmostree-skip.install");
if (!glnx_file_replace_contents_with_perms_at (rootfs_dfd, kernel_skip_path,
(guint8*)skip_kernel_install_data,
strlen (skip_kernel_install_data),
0755, 0, 0,
GLNX_FILE_REPLACE_NODATASYNC,
cancellable, error))
return FALSE;

if (!libcontainer_prep_dev (rootfs_dfd, error))
return FALSE;
/* Now actually run through librpm to install the packages. Note this bit
* will be replaced in the future with a unified core:
* https://github.com/projectatomic/rpm-ostree/issues/729
*/
g_auto(GLnxConsoleRef) console = { 0, };
g_autoptr(DnfState) hifstate = dnf_state_new ();

if (!dnf_transaction_commit (dnf_context_get_transaction (hifctx),
dnf_context_get_goal (hifctx),
hifstate,
error))
return FALSE;
guint progress_sigid = g_signal_connect (hifstate, "percentage-changed",
G_CALLBACK (on_hifstate_percentage_changed),
"Installing packages:");

g_signal_handler_disconnect (hifstate, progress_sigid);
}
glnx_console_lock (&console);

if (!libcontainer_prep_dev (rootfs_dfd, error))
return FALSE;

if (!dnf_transaction_commit (dnf_context_get_transaction (hifctx),
dnf_context_get_goal (hifctx),
hifstate, error))
return FALSE;

g_signal_handler_disconnect (hifstate, progress_sigid);
}

if (out_unmodified)
*out_unmodified = FALSE;
Expand Down Expand Up @@ -682,9 +732,32 @@ rpm_ostree_compose_context_new (const char *treefile_pathstr,
if (!rpmostree_bwrap_selftest (error))
return FALSE;

self->repo = ostree_repo_open_at (AT_FDCWD, opt_repo, cancellable, error);
if (!self->repo)
return FALSE;

if (opt_workdir_tmpfs)
g_print ("note: --workdir-tmpfs is deprecated and will be ignored\n");
if (!opt_workdir)
if (opt_ex_unified_core)
{
if (opt_workdir)
g_printerr ("note: --workdir is ignored for --ex-unified-core\n");

/* For unified core, our workdir must be underneath the repo tmp/
* in order to use hardlinks. We also really want a bare-user repo.
* We hard require that for now, but down the line we may automatically
* do a pull-local from the bare-user repo to the archive.
*/
if (ostree_repo_get_mode (self->repo) != OSTREE_REPO_MODE_BARE_USER)
return glnx_throw (error, "--ex-unified-core requires a bare-user repository");
if (!glnx_mkdtempat (ostree_repo_get_dfd (self->repo), "tmp/rpm-ostree-compose.XXXXXX", 0700,
&self->workdir_tmp, error))
return FALSE;
/* Note special handling of this aliasing in _finalize() */
self->workdir_dfd = self->workdir_tmp.fd;

}
else if (!opt_workdir)
{
if (!glnx_mkdtempat (AT_FDCWD, "/var/tmp/rpm-ostree.XXXXXX", 0700, &self->workdir_tmp, error))
return FALSE;
Expand All @@ -698,9 +771,6 @@ rpm_ostree_compose_context_new (const char *treefile_pathstr,
}

self->treefile_context_dirs = g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref);
self->repo = ostree_repo_open_at (AT_FDCWD, opt_repo, cancellable, error);
if (!self->repo)
return FALSE;

self->treefile_path = g_file_new_for_path (treefile_pathstr);

Expand Down Expand Up @@ -954,7 +1024,8 @@ impl_install_tree (RpmOstreeTreeComposeContext *self,
/* Start postprocessing */
if (!rpmostree_treefile_postprocessing (self->rootfs_dfd, self->treefile_context_dirs->pdata[0],
self->serialized_treefile, self->treefile,
next_version, cancellable, error))
next_version, opt_ex_unified_core,
cancellable, error))
return glnx_prefix_error (error, "Postprocessing");

/* Until here, we targeted "rootfs.tmp" in the working directory. Most
Expand Down Expand Up @@ -1031,7 +1102,7 @@ impl_commit_tree (RpmOstreeTreeComposeContext *self,

if (!rpmostree_rootfs_postprocess_common (self->rootfs_dfd, cancellable, error))
return EXIT_FAILURE;
if (!rpmostree_postprocess_final (self->rootfs_dfd, self->treefile,
if (!rpmostree_postprocess_final (self->rootfs_dfd, self->treefile, opt_ex_unified_core,
cancellable, error))
return EXIT_FAILURE;

Expand Down Expand Up @@ -1164,7 +1235,7 @@ rpmostree_compose_builtin_postprocess (int argc,
return EXIT_FAILURE;
if (!rpmostree_rootfs_postprocess_common (rootfs_dfd, cancellable, error))
return EXIT_FAILURE;
if (!rpmostree_postprocess_final (rootfs_dfd, treefile,
if (!rpmostree_postprocess_final (rootfs_dfd, treefile, opt_ex_unified_core,
cancellable, error))
return EXIT_FAILURE;
return EXIT_SUCCESS;
Expand Down
4 changes: 4 additions & 0 deletions src/libpriv/rpmostree-core.c
Expand Up @@ -3185,6 +3185,10 @@ rpmostree_context_assemble (RpmOstreeContext *self,
return glnx_throw_errno_prefix (error, "symlinkat(usr/bin/systemctl)");
}

/* Necessary for unified core to work with semanage calls in %post, like container-selinux */
if (!rpmostree_rootfs_prepare_selinux (tmprootfs_dfd, cancellable, error))
return FALSE;

/* We're technically deviating from RPM here by running all the %pre's
* beforehand, rather than each package's %pre & %post in order. Though I
* highly doubt this should cause any issues. The advantage of doing it
Expand Down
10 changes: 6 additions & 4 deletions src/libpriv/rpmostree-passwd-util.c
Expand Up @@ -873,6 +873,7 @@ concat_passwd_file (int rootfs_fd,

static gboolean
_data_from_json (int rootfs_dfd,
const char *dest,
GFile *treefile_dirpath,
JsonObject *treedata,
RpmOstreePasswdMigrateKind kind,
Expand Down Expand Up @@ -921,7 +922,7 @@ _data_from_json (int rootfs_dfd,
*out_found = TRUE;

const char *filebasename = passwd ? "passwd" : "group";
const char *target_etc_filename = glnx_strjoina ("etc/", filebasename);
const char *target_etc_filename = glnx_strjoina (dest, filebasename);
g_autoptr(FILE) dest_stream = open_file_stream_write_at (rootfs_dfd, target_etc_filename, "w", error);
if (!dest_stream)
return FALSE;
Expand All @@ -937,6 +938,7 @@ _data_from_json (int rootfs_dfd,
gboolean
rpmostree_generate_passwd_from_previous (OstreeRepo *repo,
int rootfs_dfd,
const char *dest,
GFile *treefile_dirpath,
GFile *previous_root,
JsonObject *treedata,
Expand All @@ -952,10 +954,10 @@ rpmostree_generate_passwd_from_previous (OstreeRepo *repo,
* is really hard because filesystem depends on setup which installs
* the files...
*/
if (!glnx_ensure_dir (rootfs_dfd, "etc", 0755, error))
if (!glnx_ensure_dir (rootfs_dfd, dest, 0755, error))
return FALSE;

if (!_data_from_json (rootfs_dfd, treefile_dirpath,
if (!_data_from_json (rootfs_dfd, dest, treefile_dirpath,
treedata, RPM_OSTREE_PASSWD_MIGRATE_PASSWD,
&found_passwd_data, cancellable, error))
return FALSE;
Expand All @@ -969,7 +971,7 @@ rpmostree_generate_passwd_from_previous (OstreeRepo *repo,
cancellable, error))
return FALSE;

if (!_data_from_json (rootfs_dfd, treefile_dirpath,
if (!_data_from_json (rootfs_dfd, dest, treefile_dirpath,
treedata, RPM_OSTREE_PASSWD_MIGRATE_GROUP,
&found_groups_data, cancellable, error))
return FALSE;
Expand Down
3 changes: 2 additions & 1 deletion src/libpriv/rpmostree-passwd-util.h
Expand Up @@ -57,6 +57,7 @@ rpmostree_passwd_migrate_except_root (int rootfs_dfd,
gboolean
rpmostree_generate_passwd_from_previous (OstreeRepo *repo,
int rootfs_dfd,
const char *dest,
GFile *treefile_dirpath,
GFile *previous_root,
JsonObject *treedata,
Expand All @@ -80,7 +81,7 @@ rpmostree_passwd_cleanup (int rootfs_dfd, GCancellable *cancellable, GError **er
gboolean
rpmostree_passwd_prepare_rpm_layering (int rootfs_dfd,
const char *merge_passwd_dir,
gboolean *out_have_passwd,
gboolean *out_have_usrlib_passwd,
GCancellable *cancellable,
GError **error);

Expand Down

0 comments on commit 1aa4c9d

Please sign in to comment.