-
Notifications
You must be signed in to change notification settings - Fork 198
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support for modules is something that has come up many times in the past. Most recently in FCOS: coreos/fedora-coreos-tracker#767 This commit adds support for both composing with modules on the server side and package layering modules (or just enabling them) on the client side. This doesn't support modules in `rpm-ostree compose extensions` yet, which is relevant for RHCOS. We can look at adding that in a follow-up.
- Loading branch information
Showing
25 changed files
with
838 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
//! Implementation of the client-side of "rpm-ostree module". | ||
// SPDX-License-Identifier: Apache-2.0 OR MIT | ||
|
||
use anyhow::{anyhow, bail, Result}; | ||
use gio::DBusProxyExt; | ||
use ostree_ext::variant_utils; | ||
use structopt::StructOpt; | ||
|
||
use crate::utils::print_treepkg_diff; | ||
|
||
#[derive(Debug, StructOpt)] | ||
#[structopt(name = "rpm-ostree module", no_version)] | ||
#[structopt(rename_all = "kebab-case")] | ||
enum Opt { | ||
/// Enable a module | ||
Enable(InstallOpts), | ||
/// Disable a module | ||
Disable(InstallOpts), | ||
/// Install a module | ||
Install(InstallOpts), | ||
/// Uninstall a module | ||
Uninstall(InstallOpts), | ||
} | ||
|
||
#[derive(Debug, StructOpt)] | ||
struct InstallOpts { | ||
#[structopt(parse(from_str))] | ||
modules: Vec<String>, | ||
#[structopt(long)] | ||
reboot: bool, | ||
#[structopt(long)] | ||
lock_finalization: bool, | ||
#[structopt(long)] | ||
dry_run: bool, | ||
#[structopt(long)] | ||
experimental: bool, | ||
} | ||
|
||
const OPT_KEY_ENABLE_MODULES: &str = "enable-modules"; | ||
const OPT_KEY_DISABLE_MODULES: &str = "disable-modules"; | ||
const OPT_KEY_INSTALL_MODULES: &str = "install-modules"; | ||
const OPT_KEY_UNINSTALL_MODULES: &str = "uninstall-modules"; | ||
|
||
pub fn entrypoint(args: &[&str]) -> Result<()> { | ||
match Opt::from_iter(args.iter().skip(1)) { | ||
Opt::Enable(ref opts) => enable(opts), | ||
Opt::Disable(ref opts) => disable(opts), | ||
Opt::Install(ref opts) => install(opts), | ||
Opt::Uninstall(ref opts) => uninstall(opts), | ||
} | ||
} | ||
|
||
// XXX: Should split out a lot of the below into a more generic Rust wrapper around | ||
// UpdateDeployment() like we have on the C side. | ||
|
||
fn get_modifiers_variant(key: &str, modules: &[String]) -> Result<glib::Variant> { | ||
let r = glib::VariantDict::new(None); | ||
r.insert_value(key, &crate::variant_utils::new_variant_strv(modules)); | ||
Ok(r.end()) | ||
} | ||
|
||
fn get_options_variant(opts: &InstallOpts) -> Result<glib::Variant> { | ||
let r = glib::VariantDict::new(None); | ||
r.insert("no-pull-base", &true); | ||
r.insert("reboot", &opts.reboot); | ||
r.insert("lock-finalization", &opts.lock_finalization); | ||
r.insert("dry-run", &opts.dry_run); | ||
Ok(r.end()) | ||
} | ||
|
||
fn enable(opts: &InstallOpts) -> Result<()> { | ||
modules_impl(OPT_KEY_ENABLE_MODULES, opts) | ||
} | ||
|
||
fn disable(opts: &InstallOpts) -> Result<()> { | ||
modules_impl(OPT_KEY_DISABLE_MODULES, opts) | ||
} | ||
|
||
fn install(opts: &InstallOpts) -> Result<()> { | ||
modules_impl(OPT_KEY_INSTALL_MODULES, opts) | ||
} | ||
|
||
fn uninstall(opts: &InstallOpts) -> Result<()> { | ||
modules_impl(OPT_KEY_UNINSTALL_MODULES, opts) | ||
} | ||
|
||
fn modules_impl(key: &str, opts: &InstallOpts) -> Result<()> { | ||
if !opts.experimental { | ||
bail!("Modularity support is experimental and subject to change. Use --experimental."); | ||
} | ||
|
||
if opts.modules.is_empty() { | ||
bail!("At least one module must be specified"); | ||
} | ||
|
||
let client = &mut crate::client::ClientConnection::new()?; | ||
let previous_deployment = client | ||
.get_os_proxy() | ||
.get_cached_property("DefaultDeployment") | ||
.ok_or_else(|| anyhow!("Failed to find default-deployment property"))?; | ||
let modifiers = get_modifiers_variant(key, &opts.modules)?; | ||
let options = get_options_variant(opts)?; | ||
let params = variant_utils::new_variant_tuple(&[modifiers, options]); | ||
let reply = &client.get_os_proxy().call_sync( | ||
"UpdateDeployment", | ||
Some(¶ms), | ||
gio::DBusCallFlags::NONE, | ||
-1, | ||
gio::NONE_CANCELLABLE, | ||
)?; | ||
let reply_child = crate::variant_utils::variant_tuple_get(reply, 0) | ||
.ok_or_else(|| anyhow!("Invalid reply"))?; | ||
let txn_address = reply_child | ||
.get_str() | ||
.ok_or_else(|| anyhow!("Expected string transaction address"))?; | ||
client.transaction_connect_progress_sync(txn_address)?; | ||
if opts.dry_run { | ||
println!("Exiting because of '--dry-run' option"); | ||
} else if !opts.reboot { | ||
let new_deployment = client | ||
.get_os_proxy() | ||
.get_cached_property("DefaultDeployment") | ||
.ok_or_else(|| anyhow!("Failed to find default-deployment property"))?; | ||
if previous_deployment != new_deployment { | ||
print_treepkg_diff("/"); | ||
} | ||
} | ||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.