Skip to content

Commit 8fe9633

Browse files
authored
Merge pull request #1602 from cgwalters/store-cleanups
store: Move inner merge commit writing to a helper function
2 parents 68c4e4d + ac08093 commit 8fe9633

File tree

1 file changed

+140
-114
lines changed

1 file changed

+140
-114
lines changed

crates/ostree-ext/src/container/store.rs

Lines changed: 140 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -940,6 +940,135 @@ impl ImageImporter {
940940
})
941941
}
942942

943+
/// Generate a single ostree commit that combines all layers, and also
944+
/// includes container image metadata such as the manifest and config.
945+
fn write_merge_commit_impl(
946+
repo: &ostree::Repo,
947+
base_commit: Option<&str>,
948+
layer_commits: &[String],
949+
have_derived_layers: bool,
950+
metadata: glib::Variant,
951+
timestamp: u64,
952+
ostree_ref: &str,
953+
no_imgref: bool,
954+
disable_gc: bool,
955+
cancellable: Option<&gio::Cancellable>,
956+
) -> Result<Box<LayeredImageState>> {
957+
use rustix::fd::AsRawFd;
958+
959+
let txn = repo.auto_transaction(cancellable)?;
960+
961+
let devino = ostree::RepoDevInoCache::new();
962+
let repodir = Dir::reopen_dir(&repo.dfd_borrow())?;
963+
let repo_tmp = repodir.open_dir("tmp")?;
964+
let td = cap_std_ext::cap_tempfile::TempDir::new_in(&repo_tmp)?;
965+
966+
let rootpath = "root";
967+
let checkout_mode = if repo.mode() == ostree::RepoMode::Bare {
968+
ostree::RepoCheckoutMode::None
969+
} else {
970+
ostree::RepoCheckoutMode::User
971+
};
972+
let mut checkout_opts = ostree::RepoCheckoutAtOptions {
973+
mode: checkout_mode,
974+
overwrite_mode: ostree::RepoCheckoutOverwriteMode::UnionFiles,
975+
devino_to_csum_cache: Some(devino.clone()),
976+
no_copy_fallback: true,
977+
force_copy_zerosized: true,
978+
process_whiteouts: false,
979+
..Default::default()
980+
};
981+
if let Some(base) = base_commit.as_ref() {
982+
repo.checkout_at(
983+
Some(&checkout_opts),
984+
(*td).as_raw_fd(),
985+
rootpath,
986+
&base,
987+
cancellable,
988+
)
989+
.context("Checking out base commit")?;
990+
}
991+
992+
// Layer all subsequent commits
993+
checkout_opts.process_whiteouts = true;
994+
for commit in layer_commits {
995+
tracing::debug!("Unpacking {commit}");
996+
repo.checkout_at(
997+
Some(&checkout_opts),
998+
(*td).as_raw_fd(),
999+
rootpath,
1000+
&commit,
1001+
cancellable,
1002+
)
1003+
.with_context(|| format!("Checking out layer {commit}"))?;
1004+
}
1005+
1006+
let root_dir = td.open_dir(rootpath)?;
1007+
1008+
let modifier =
1009+
ostree::RepoCommitModifier::new(ostree::RepoCommitModifierFlags::empty(), None);
1010+
modifier.set_devino_cache(&devino);
1011+
// If we have derived layers, then we need to handle the case where
1012+
// the derived layers include custom policy. Just relabel everything
1013+
// in this case.
1014+
if have_derived_layers {
1015+
let sepolicy = ostree::SePolicy::new_at(root_dir.as_raw_fd(), cancellable)?;
1016+
tracing::debug!("labeling from merged tree");
1017+
modifier.set_sepolicy(Some(&sepolicy));
1018+
} else if let Some(base) = base_commit.as_ref() {
1019+
tracing::debug!("labeling from base tree");
1020+
// TODO: We can likely drop this; we know all labels should be pre-computed.
1021+
modifier.set_sepolicy_from_commit(repo, &base, cancellable)?;
1022+
} else {
1023+
panic!("Unexpected state: no derived layers and no base")
1024+
}
1025+
1026+
cleanup_root(&root_dir)?;
1027+
1028+
let mt = ostree::MutableTree::new();
1029+
repo.write_dfd_to_mtree(
1030+
(*td).as_raw_fd(),
1031+
rootpath,
1032+
&mt,
1033+
Some(&modifier),
1034+
cancellable,
1035+
)
1036+
.context("Writing merged filesystem to mtree")?;
1037+
1038+
let merged_root = repo
1039+
.write_mtree(&mt, cancellable)
1040+
.context("Writing mtree")?;
1041+
let merged_root = merged_root.downcast::<ostree::RepoFile>().unwrap();
1042+
// The merge has the base commit as a parent, if it exists. See
1043+
// https://github.com/ostreedev/ostree/pull/3523
1044+
let parent = base_commit.as_deref();
1045+
let merged_commit = repo
1046+
.write_commit_with_time(
1047+
parent,
1048+
None,
1049+
None,
1050+
Some(&metadata),
1051+
&merged_root,
1052+
timestamp,
1053+
cancellable,
1054+
)
1055+
.context("Writing commit")?;
1056+
if !no_imgref {
1057+
repo.transaction_set_ref(None, ostree_ref, Some(merged_commit.as_str()));
1058+
}
1059+
txn.commit(cancellable)?;
1060+
1061+
if !disable_gc {
1062+
let n: u32 = gc_image_layers_impl(repo, cancellable)?;
1063+
tracing::debug!("pruned {n} layers");
1064+
}
1065+
1066+
// Here we re-query state just to run through the same code path,
1067+
// though it'd be cheaper to synthesize it from the data we already have.
1068+
let state = query_image_commit(repo, &merged_commit)?;
1069+
Ok(state)
1070+
}
1071+
9431072
/// Import a layered container image.
9441073
///
9451074
/// If enabled, this will also prune unused container image layers.
@@ -1080,121 +1209,18 @@ impl ImageImporter {
10801209
let repo = self.repo;
10811210
let mut state = crate::tokio_util::spawn_blocking_cancellable_flatten(
10821211
move |cancellable| -> Result<Box<LayeredImageState>> {
1083-
use rustix::fd::AsRawFd;
1084-
1085-
let cancellable = Some(cancellable);
1086-
let repo = &repo;
1087-
let txn = repo.auto_transaction(cancellable)?;
1088-
1089-
let devino = ostree::RepoDevInoCache::new();
1090-
let repodir = Dir::reopen_dir(&repo.dfd_borrow())?;
1091-
let repo_tmp = repodir.open_dir("tmp")?;
1092-
let td = cap_std_ext::cap_tempfile::TempDir::new_in(&repo_tmp)?;
1093-
1094-
let rootpath = "root";
1095-
let checkout_mode = if repo.mode() == ostree::RepoMode::Bare {
1096-
ostree::RepoCheckoutMode::None
1097-
} else {
1098-
ostree::RepoCheckoutMode::User
1099-
};
1100-
let mut checkout_opts = ostree::RepoCheckoutAtOptions {
1101-
mode: checkout_mode,
1102-
overwrite_mode: ostree::RepoCheckoutOverwriteMode::UnionFiles,
1103-
devino_to_csum_cache: Some(devino.clone()),
1104-
no_copy_fallback: true,
1105-
force_copy_zerosized: true,
1106-
process_whiteouts: false,
1107-
..Default::default()
1108-
};
1109-
if let Some(base) = base_commit.as_ref() {
1110-
repo.checkout_at(
1111-
Some(&checkout_opts),
1112-
(*td).as_raw_fd(),
1113-
rootpath,
1114-
&base,
1115-
cancellable,
1116-
)
1117-
.context("Checking out base commit")?;
1118-
}
1119-
1120-
// Layer all subsequent commits
1121-
checkout_opts.process_whiteouts = true;
1122-
for commit in layer_commits {
1123-
tracing::debug!("Unpacking {commit}");
1124-
repo.checkout_at(
1125-
Some(&checkout_opts),
1126-
(*td).as_raw_fd(),
1127-
rootpath,
1128-
&commit,
1129-
cancellable,
1130-
)
1131-
.with_context(|| format!("Checking out layer {commit}"))?;
1132-
}
1133-
1134-
let root_dir = td.open_dir(rootpath)?;
1135-
1136-
let modifier =
1137-
ostree::RepoCommitModifier::new(ostree::RepoCommitModifierFlags::empty(), None);
1138-
modifier.set_devino_cache(&devino);
1139-
// If we have derived layers, then we need to handle the case where
1140-
// the derived layers include custom policy. Just relabel everything
1141-
// in this case.
1142-
if have_derived_layers {
1143-
let sepolicy = ostree::SePolicy::new_at(root_dir.as_raw_fd(), cancellable)?;
1144-
tracing::debug!("labeling from merged tree");
1145-
modifier.set_sepolicy(Some(&sepolicy));
1146-
} else if let Some(base) = base_commit.as_ref() {
1147-
tracing::debug!("labeling from base tree");
1148-
// TODO: We can likely drop this; we know all labels should be pre-computed.
1149-
modifier.set_sepolicy_from_commit(repo, &base, cancellable)?;
1150-
} else {
1151-
unreachable!()
1152-
}
1153-
1154-
cleanup_root(&root_dir)?;
1155-
1156-
let mt = ostree::MutableTree::new();
1157-
repo.write_dfd_to_mtree(
1158-
(*td).as_raw_fd(),
1159-
rootpath,
1160-
&mt,
1161-
Some(&modifier),
1162-
cancellable,
1212+
Self::write_merge_commit_impl(
1213+
&repo,
1214+
base_commit.as_deref(),
1215+
&layer_commits,
1216+
have_derived_layers,
1217+
metadata,
1218+
timestamp,
1219+
&ostree_ref,
1220+
self.no_imgref,
1221+
self.disable_gc,
1222+
Some(cancellable),
11631223
)
1164-
.context("Writing merged filesystem to mtree")?;
1165-
1166-
let merged_root = repo
1167-
.write_mtree(&mt, cancellable)
1168-
.context("Writing mtree")?;
1169-
let merged_root = merged_root.downcast::<ostree::RepoFile>().unwrap();
1170-
// The merge has the base commit as a parent, if it exists. See
1171-
// https://github.com/ostreedev/ostree/pull/3523
1172-
let parent = base_commit.as_deref();
1173-
let merged_commit = repo
1174-
.write_commit_with_time(
1175-
parent,
1176-
None,
1177-
None,
1178-
Some(&metadata),
1179-
&merged_root,
1180-
timestamp,
1181-
cancellable,
1182-
)
1183-
.context("Writing commit")?;
1184-
if !self.no_imgref {
1185-
repo.transaction_set_ref(None, &ostree_ref, Some(merged_commit.as_str()));
1186-
}
1187-
txn.commit(cancellable)?;
1188-
1189-
if !self.disable_gc {
1190-
let n: u32 = gc_image_layers_impl(repo, cancellable)?;
1191-
tracing::debug!("pruned {n} layers");
1192-
}
1193-
1194-
// Here we re-query state just to run through the same code path,
1195-
// though it'd be cheaper to synthesize it from the data we already have.
1196-
let state = query_image_commit(repo, &merged_commit)?;
1197-
Ok(state)
11981224
},
11991225
)
12001226
.await?;

0 commit comments

Comments
 (0)