diff --git a/.cci.jenkinsfile b/.cci.jenkinsfile index 511236c7f7..305f12a5cc 100644 --- a/.cci.jenkinsfile +++ b/.cci.jenkinsfile @@ -3,7 +3,7 @@ stage("Build") { parallel rpms: { def n = 4 - buildPod(memory: "4Gi", cpu: "${n}") { + buildPod(memory: "6Gi", cpu: "${n}") { checkout scm // 2:1 job to CPU at most should keep us from getting kicked out shwrap("""RPM_BUILD_NCPUS=${n} CARGO_BUILD_JOBS=${n} ./ci/coreosci-rpmbuild.sh""") diff --git a/Cargo.lock b/Cargo.lock index 4f7759507c..6d7d8c0d64 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,6 +8,18 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "ahash" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +dependencies = [ + "cfg-if", + "getrandom", + "once_cell", + "version_check", +] + [[package]] name = "aho-corasick" version = "1.0.1" @@ -119,12 +131,34 @@ dependencies = [ "tokio", ] +[[package]] +name = "async-trait" +version = "0.1.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc6dde6e4ed435a4c1ee4e73592f5ba9da2151af10076cc04858746af9352d09" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.26", +] + [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "backoff" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62ddb9cb1ec0a098ad4bbf9344d0713fa193ae1a80af55febcff2627b6a00c1" +dependencies = [ + "getrandom", + "instant", + "rand", +] + [[package]] name = "base64" version = "0.13.1" @@ -173,9 +207,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.3.1" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6776fc96284a0bb647b615056fc496d1fe1644a7ab01829818a6d91cae888b84" +checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" [[package]] name = "block-buffer" @@ -186,6 +220,42 @@ dependencies = [ "generic-array", ] +[[package]] +name = "bootc-lib" +version = "0.1.0" +source = "git+https://github.com/containers/bootc.git?branch=main#221e382cbe5fc5ff45b2064370cf58248406d4b6" +dependencies = [ + "anyhow", + "camino", + "cap-std-ext 2.0.0", + "clap", + "fn-error-context", + "gvariant", + "hex", + "indicatif", + "k8s-openapi", + "kube", + "libc", + "liboverdrop", + "nix 0.25.1", + "once_cell", + "openssl", + "ostree-ext 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)", + "regex", + "rustix 0.37.20", + "schemars", + "serde", + "serde_json", + "serde_with", + "serde_yaml", + "tempfile", + "tokio", + "tokio-util", + "toml", + "tracing", + "uuid 1.3.2", +] + [[package]] name = "build-env" version = "0.3.1" @@ -209,6 +279,9 @@ name = "camino" version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c530edf18f37068ac2d977409ed5cd50d53d73bc653c7647b48eb78976ac9ae2" +dependencies = [ + "serde", +] [[package]] name = "cap-primitives" @@ -222,7 +295,7 @@ dependencies = [ "io-lifetimes", "ipnet", "maybe-owned", - "rustix 0.37.19", + "rustix 0.37.20", "windows-sys 0.48.0", "winx", ] @@ -237,7 +310,7 @@ dependencies = [ "cap-primitives", "io-extras", "io-lifetimes", - "rustix 0.37.19", + "rustix 0.37.20", ] [[package]] @@ -257,7 +330,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6012b1e726e3e3ccf8151e2dc9cb454e593e0e7623b0e35464f5e62a15158c27" dependencies = [ "cap-tempfile", - "rustix 0.37.19", + "rustix 0.37.20", ] [[package]] @@ -268,7 +341,7 @@ checksum = "6fd9864347f55a9c31de436ec9d7d3577476f3e6eeb3cc44ae2204de9164f78d" dependencies = [ "cap-std", "rand", - "rustix 0.37.19", + "rustix 0.37.20", "uuid 1.3.2", ] @@ -323,9 +396,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.3.2" +version = "4.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "401a4694d2bf92537b6867d94de48c4842089645fdcdf6c71865b175d836e9c2" +checksum = "3eab9e8ceb9afdade1ab3f0fd8dbce5b1b2f468ad653baf10e771781b2b67b73" dependencies = [ "clap_builder", "clap_derive", @@ -334,27 +407,26 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.3.1" +version = "4.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72394f3339a76daf211e57d4bcb374410f3965dcc606dd0e03738c7888766980" +checksum = "9f2763db829349bf00cfc06251268865ed4363b93a943174f638daf3ecdba2cd" dependencies = [ "anstream", "anstyle", - "bitflags 1.3.2", "clap_lex", "strsim", ] [[package]] name = "clap_derive" -version = "4.3.2" +version = "4.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8cd2b2a819ad6eec39e8f1d6b53001af1e5469f8c177579cdaeb313115b825f" +checksum = "54a9bb5758fc5dfe728d1019941681eccaf0cf8a4189b692a0ee2f2ecf90a050" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.26", ] [[package]] @@ -551,9 +623,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.95" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "109308c20e8445959c2792e81871054c6a17e6976489a93d2769641a2ba5839c" +checksum = "5032837c1384de3708043de9d4e97bb91290faca6c16529a28aa340592a78166" dependencies = [ "cc", "cxxbridge-flags", @@ -563,9 +635,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.95" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daf4c6755cdf10798b97510e0e2b3edb9573032bd9379de8fffa59d68165494f" +checksum = "51368b3d0dbf356e10fcbfd455a038503a105ee556f7ee79b6bb8c53a7247456" dependencies = [ "cc", "codespan-reporting", @@ -573,24 +645,34 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.15", + "syn 2.0.26", ] [[package]] name = "cxxbridge-flags" -version = "1.0.95" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "882074421238e84fe3b4c65d0081de34e5b323bf64555d3e61991f76eb64a7bb" +checksum = "0d9062157072e4aafc8e56ceaf8325ce850c5ae37578c852a0d4de2cecdded13" [[package]] name = "cxxbridge-macro" -version = "1.0.95" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a076022ece33e7686fb76513518e219cca4fce5750a8ae6d1ce6c0f48fd1af9" +checksum = "cf01e8a540f5a4e0f284595834f81cf88572f244b768f051724537afa99a2545" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.26", +] + +[[package]] +name = "darling" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" +dependencies = [ + "darling_core 0.13.4", + "darling_macro 0.13.4", ] [[package]] @@ -599,8 +681,22 @@ version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" dependencies = [ - "darling_core", - "darling_macro", + "darling_core 0.14.4", + "darling_macro 0.14.4", +] + +[[package]] +name = "darling_core" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 1.0.109", ] [[package]] @@ -617,13 +713,35 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "darling_macro" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" +dependencies = [ + "darling_core 0.13.4", + "quote", + "syn 1.0.109", +] + [[package]] name = "darling_macro" version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" dependencies = [ - "darling_core", + "darling_core 0.14.4", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", "quote", "syn 1.0.109", ] @@ -643,7 +761,7 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f91d4cfa921f1c05904dc3c57b4a32c38aed3340cce209f3a6fd1478babafc4" dependencies = [ - "darling", + "darling 0.14.4", "proc-macro2", "quote", "syn 1.0.109", @@ -670,6 +788,27 @@ dependencies = [ "subtle", ] +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + [[package]] name = "dlv-list" version = "0.5.0" @@ -679,6 +818,12 @@ dependencies = [ "const-random", ] +[[package]] +name = "dyn-clone" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "304e6508efa593091e97a9abbc10f90aa7ca635b6d2784feff3c89d41dd12272" + [[package]] name = "either" version = "1.8.1" @@ -794,7 +939,7 @@ checksum = "2cd66269887534af4b0c3e3337404591daa8dc8b9b2b3db71f9523beb4bafb41" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.26", ] [[package]] @@ -830,7 +975,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.26", ] [[package]] @@ -861,7 +1006,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7833d0f115a013d51c55950a3b09d30e4b057be9961b709acb9b5b17a1108861" dependencies = [ "io-lifetimes", - "rustix 0.37.19", + "rustix 0.37.20", "windows-sys 0.48.0", ] @@ -921,7 +1066,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.26", ] [[package]] @@ -1187,6 +1332,12 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "http-range-header" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" + [[package]] name = "httparse" version = "1.8.0" @@ -1229,6 +1380,36 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-openssl" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6ee5d7a8f718585d1c3c61dfde28ef5b0bb14734b4db13f5ada856cdc6c612b" +dependencies = [ + "http", + "hyper", + "linked_hash_set", + "once_cell", + "openssl", + "openssl-sys", + "parking_lot", + "tokio", + "tokio-openssl", + "tower-layer", +] + +[[package]] +name = "hyper-timeout" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" +dependencies = [ + "hyper", + "pin-project-lite", + "tokio", + "tokio-io-timeout", +] + [[package]] name = "hyper-tls" version = "0.5.0" @@ -1294,11 +1475,12 @@ dependencies = [ [[package]] name = "indicatif" -version = "0.17.3" +version = "0.17.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cef509aa9bc73864d6756f0d34d35504af3cf0844373afe9b8669a5b8005a729" +checksum = "8ff8cc23a7393a397ed1d7f56e6365cba772aba9f9912ab968b03043c395d057" dependencies = [ "console", + "instant", "number_prefix", "portable-atomic", "unicode-width", @@ -1354,7 +1536,7 @@ checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" dependencies = [ "hermit-abi 0.3.1", "io-lifetimes", - "rustix 0.37.19", + "rustix 0.37.20", "windows-sys 0.48.0", ] @@ -1382,6 +1564,150 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "json-patch" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f54898088ccb91df1b492cc80029a6fdf1c48ca0db7c6822a8babad69c94658" +dependencies = [ + "serde", + "serde_json", + "thiserror", + "treediff", +] + +[[package]] +name = "jsonpath_lib" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaa63191d68230cccb81c5aa23abd53ed64d83337cacbb25a7b8c7979523774f" +dependencies = [ + "log", + "serde", + "serde_json", +] + +[[package]] +name = "k8s-openapi" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd990069640f9db34b3b0f7a1afc62a05ffaa3be9b66aa3c313f58346df7f788" +dependencies = [ + "base64 0.21.0", + "bytes", + "chrono", + "http", + "percent-encoding", + "serde", + "serde-value", + "serde_json", + "url", +] + +[[package]] +name = "kube" +version = "0.83.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f468b2fa6c5ef92117813238758f79e394c2d7688bd6faa3e77243f90260b0" +dependencies = [ + "k8s-openapi", + "kube-client", + "kube-core", + "kube-derive", + "kube-runtime", +] + +[[package]] +name = "kube-client" +version = "0.83.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "337eb332d253036adc3247936248d0742c6c743f51eb38a684fd9b3b2878b27c" +dependencies = [ + "base64 0.20.0", + "bytes", + "chrono", + "dirs-next", + "either", + "futures", + "http", + "http-body", + "hyper", + "hyper-openssl", + "hyper-timeout", + "jsonpath_lib", + "k8s-openapi", + "kube-core", + "openssl", + "pem", + "pin-project", + "secrecy", + "serde", + "serde_json", + "serde_yaml", + "thiserror", + "tokio", + "tokio-util", + "tower", + "tower-http", + "tracing", +] + +[[package]] +name = "kube-core" +version = "0.83.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f924177ad71936cfe612641b45bb9879890696d3c026f0846423529f4fa449af" +dependencies = [ + "chrono", + "form_urlencoded", + "http", + "json-patch", + "k8s-openapi", + "once_cell", + "schemars", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "kube-derive" +version = "0.83.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ce7c7a14cf3fe567ca856de41db0d61394867675cfb0d65094c55f0fa2df2e0" +dependencies = [ + "darling 0.14.4", + "proc-macro2", + "quote", + "serde_json", + "syn 1.0.109", +] + +[[package]] +name = "kube-runtime" +version = "0.83.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d5e4d09df25250ffcb09df3f31105a5f49eb8f8a08da9b776ea5b6431ec476f" +dependencies = [ + "ahash", + "async-trait", + "backoff", + "derivative", + "futures", + "json-patch", + "k8s-openapi", + "kube-client", + "parking_lot", + "pin-project", + "serde", + "serde_json", + "smallvec", + "thiserror", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -1405,6 +1731,15 @@ dependencies = [ "system-deps", ] +[[package]] +name = "liboverdrop" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08e5373d7512834e2fbbe4100111483a99c28ca3818639f67ab2337672301f8e" +dependencies = [ + "log", +] + [[package]] name = "libsystemd" version = "0.5.0" @@ -1447,13 +1782,28 @@ dependencies = [ [[package]] name = "link-cplusplus" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" +checksum = "9d240c6f7e1ba3a28b0249f774e6a9dd0175054b52dfbb61b16eb8505c3785c9" dependencies = [ "cc", ] +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + +[[package]] +name = "linked_hash_set" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47186c6da4d81ca383c7c47c1bfc80f4b95f4720514d860a5407aaf4233f9588" +dependencies = [ + "linked-hash-map", +] + [[package]] name = "linux-raw-sys" version = "0.1.4" @@ -1466,6 +1816,16 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b64f40e5e03e0d54f03845c8197d0291253cdbedfb1cb46b13c2c117554a9f4c" +[[package]] +name = "lock_api" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +dependencies = [ + "autocfg", + "scopeguard", +] + [[package]] name = "log" version = "0.4.17" @@ -1508,7 +1868,7 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffc89ccdc6e10d6907450f753537ebc5c5d3460d2e4e62ea74bd571db62c0f9e" dependencies = [ - "rustix 0.37.19", + "rustix 0.37.20", ] [[package]] @@ -1602,6 +1962,20 @@ dependencies = [ "memoffset 0.6.5", ] +[[package]] +name = "nix" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4" +dependencies = [ + "autocfg", + "bitflags 1.3.2", + "cfg-if", + "libc", + "memoffset 0.6.5", + "pin-utils", +] + [[package]] name = "nix" version = "0.26.2" @@ -1693,9 +2067,9 @@ checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "openssl" -version = "0.10.52" +version = "0.10.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01b8574602df80f7b85fdfc5392fa884a4e3b3f4f35402c070ab34c3d3f78d56" +checksum = "69b3f656a17a6cbc115b5c7a40c616947d213ba182135b014d6051b73ab6f019" dependencies = [ "bitflags 1.3.2", "cfg-if", @@ -1714,7 +2088,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.26", ] [[package]] @@ -1725,9 +2099,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.87" +version = "0.9.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e17f59264b2809d77ae94f0e1ebabc434773f370d6ca667bd223ea10e06cc7e" +checksum = "c2ce0f250f34a308dcfdbb351f511359857d4ed2134ba715a4eadd46e1ffd617" dependencies = [ "cc", "libc", @@ -1735,6 +2109,15 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "ordered-float" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7940cf2ca942593318d07fcf2596cdca60a85c9e7fab408a5e21a4f9dcd40d87" +dependencies = [ + "num-traits", +] + [[package]] name = "ordered-multimap" version = "0.6.0" @@ -1775,9 +2158,9 @@ dependencies = [ [[package]] name = "ostree-ext" -version = "0.11.0" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8903d59c4a56794b6ef8a2b11a5674fe85b370f1da33ae34450a6de1e39a20d6" +checksum = "8511513a60fa0c20a84ba8d30255286687c848bec21d24cd3dd4d16ecf48123b" dependencies = [ "anyhow", "async-compression 0.3.15", @@ -1803,7 +2186,48 @@ dependencies = [ "ostree", "pin-project", "regex", - "rustix 0.37.19", + "rustix 0.37.20", + "serde", + "serde_json", + "tar", + "tempfile", + "term_size", + "tokio", + "tokio-stream", + "tokio-util", + "tracing", +] + +[[package]] +name = "ostree-ext" +version = "0.11.3" +source = "git+https://github.com/ostreedev/ostree-rs-ext.git?rev=ea853c082c09594e1559e55b91d011994feb855b#ea853c082c09594e1559e55b91d011994feb855b" +dependencies = [ + "anyhow", + "async-compression 0.3.15", + "bitflags 1.3.2", + "camino", + "cap-std-ext 2.0.0", + "cap-tempfile", + "chrono", + "clap", + "containers-image-proxy", + "flate2", + "fn-error-context", + "futures-util", + "gvariant", + "hex", + "indicatif", + "io-lifetimes", + "libc", + "libsystemd", + "olpc-cjson", + "once_cell", + "openssl", + "ostree", + "pin-project", + "regex", + "rustix 0.37.20", "serde", "serde_json", "tar", @@ -1834,12 +2258,44 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.3.5", + "smallvec", + "windows-targets 0.48.0", +] + [[package]] name = "paste" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" +[[package]] +name = "pem" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" +dependencies = [ + "base64 0.13.1", +] + [[package]] name = "percent-encoding" version = "2.2.0" @@ -1928,9 +2384,9 @@ checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" [[package]] name = "portable-atomic" -version = "0.3.19" +version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26f6a7b87c2e435a3241addceeeff740ff8b7e76b74c13bf9acb17fa454ea00b" +checksum = "767eb9f07d4a5ebcb39bbf2d452058a93c011373abf6832e24194a1c3f004794" [[package]] name = "ppv-lite86" @@ -1980,18 +2436,18 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.59" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.26" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +checksum = "5fe8a65d69dd0808184ebb5f836ab526bb259db23c657efa38711b1072ee47f0" dependencies = [ "proc-macro2", ] @@ -2066,6 +2522,17 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "redox_users" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +dependencies = [ + "getrandom", + "redox_syscall 0.2.16", + "thiserror", +] + [[package]] name = "ref-cast" version = "1.0.16" @@ -2083,18 +2550,18 @@ checksum = "8d2275aab483050ab2a7364c1a46604865ee7d6906684e08db0f090acf74f9e7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.26", ] [[package]] name = "regex" -version = "1.8.1" +version = "1.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af83e617f331cc6ae2da5443c602dfa5af81e517212d9d611a5b3ba1777b5370" +checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.7.1", + "regex-syntax 0.7.2", ] [[package]] @@ -2114,9 +2581,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c" +checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" [[package]] name = "reqwest" @@ -2173,7 +2640,8 @@ version = "0.1.0" dependencies = [ "anyhow", "binread", - "bitflags 2.3.1", + "bitflags 2.3.3", + "bootc-lib", "camino", "cap-primitives", "cap-std", @@ -2200,7 +2668,7 @@ dependencies = [ "once_cell", "openssl", "os-release", - "ostree-ext", + "ostree-ext 0.11.3 (git+https://github.com/ostreedev/ostree-rs-ext.git?rev=ea853c082c09594e1559e55b91d011994feb855b)", "paste", "phf", "rand", @@ -2209,7 +2677,7 @@ dependencies = [ "reqwest", "rpmostree-client", "rust-ini", - "rustix 0.37.19", + "rustix 0.37.20", "serde", "serde_derive", "serde_json", @@ -2252,9 +2720,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.19" +version = "0.37.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d" +checksum = "b96e891d04aa506a6d1f318d2771bcb1c7dfda84e126660ace067c9b474bb2c0" dependencies = [ "bitflags 1.3.2", "errno", @@ -2287,6 +2755,30 @@ dependencies = [ "windows-sys 0.42.0", ] +[[package]] +name = "schemars" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02c613288622e5f0c3fdc5dbd4db1c5fbe752746b1d1a56a0630b78fd00de44f" +dependencies = [ + "dyn-clone", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109da1e6b197438deb6db99952990c7f959572794b80ff93707d55a232545e7c" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 1.0.109", +] + [[package]] name = "scopeguard" version = "1.1.0" @@ -2299,6 +2791,16 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" +[[package]] +name = "secrecy" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e" +dependencies = [ + "serde", + "zeroize", +] + [[package]] name = "security-framework" version = "2.8.2" @@ -2330,22 +2832,43 @@ checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" [[package]] name = "serde" -version = "1.0.163" +version = "1.0.164" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2" +checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" dependencies = [ "serde_derive", ] +[[package]] +name = "serde-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" +dependencies = [ + "ordered-float", + "serde", +] + [[package]] name = "serde_derive" -version = "1.0.163" +version = "1.0.164" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" +checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.26", +] + +[[package]] +name = "serde_derive_internals" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", ] [[package]] @@ -2354,6 +2877,7 @@ version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" dependencies = [ + "indexmap", "itoa", "ryu", "serde", @@ -2380,6 +2904,28 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_with" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678b5a069e50bf00ecd22d0cd8ddf7c236f68581b03db652061ed5eb13a312ff" +dependencies = [ + "serde", + "serde_with_macros", +] + +[[package]] +name = "serde_with_macros" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082" +dependencies = [ + "darling 0.13.4", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "serde_yaml" version = "0.9.21" @@ -2484,9 +3030,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.15" +version = "2.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" +checksum = "45c3457aacde3c65315de5031ec191ce46604304d2446e803d71ade03308d970" dependencies = [ "proc-macro2", "quote", @@ -2547,7 +3093,7 @@ dependencies = [ "cfg-if", "fastrand", "redox_syscall 0.3.5", - "rustix 0.37.19", + "rustix 0.37.20", "windows-sys 0.45.0", ] @@ -2587,7 +3133,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.26", ] [[package]] @@ -2653,6 +3199,16 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "tokio-io-timeout" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" +dependencies = [ + "pin-project-lite", + "tokio", +] + [[package]] name = "tokio-macros" version = "2.1.0" @@ -2661,7 +3217,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.26", ] [[package]] @@ -2674,6 +3230,18 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-openssl" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08f9ffb7809f1b20c1b398d92acf4cc719874b3b2b2d9ea2f09b4a80350878a" +dependencies = [ + "futures-util", + "openssl", + "openssl-sys", + "tokio", +] + [[package]] name = "tokio-stream" version = "0.1.14" @@ -2696,6 +3264,7 @@ dependencies = [ "futures-core", "futures-sink", "pin-project-lite", + "slab", "tokio", "tracing", ] @@ -2734,6 +3303,50 @@ dependencies = [ "winnow", ] +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55ae70283aba8d2a8b411c695c437fe25b8b5e44e23e780662002fc72fb47a82" +dependencies = [ + "base64 0.21.0", + "bitflags 2.3.3", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-range-header", + "mime", + "pin-project-lite", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + [[package]] name = "tower-service" version = "0.3.2" @@ -2747,6 +3360,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ "cfg-if", + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -2760,7 +3374,7 @@ checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.26", ] [[package]] @@ -2802,6 +3416,15 @@ dependencies = [ "tracing-log", ] +[[package]] +name = "treediff" +version = "4.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52984d277bdf2a751072b5df30ec0377febdb02f7696d64c2d7d54630bac4303" +dependencies = [ + "serde_json", +] + [[package]] name = "try-lock" version = "0.2.4" @@ -3253,3 +3876,9 @@ dependencies = [ "reqwest", "xml-rs", ] + +[[package]] +name = "zeroize" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" diff --git a/Cargo.toml b/Cargo.toml index c414e92e7a..56d315b5bb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,6 +45,7 @@ rpm = "4" anyhow = "1.0.69" binread = "2.2.0" bitflags = "2.3" +bootc = { git = "https://github.com/containers/bootc.git", branch = "main", package = "bootc-lib"} camino = "1.1.1" cap-std-ext = "2.0" cap-std = { version = "1.0.3", features = ["fs_utf8"] } @@ -55,7 +56,7 @@ cap-primitives = "1.0.3" cap-tempfile = "1.0.15" chrono = { version = "0.4.26", features = ["serde"] } clap = { version = "4.3", features = ["derive"] } -cxx = "1.0.95" +cxx = "1.0.101" envsubst = "0.2.1" either = "1.8.1" env_logger = "0.10.0" @@ -63,26 +64,26 @@ fail = { version = "0.5", features = ["failpoints"] } fn-error-context = "0.2.0" futures = "0.3.28" indoc = "2.0.1" -indicatif = "0.17.3" +indicatif = "0.17.5" is-terminal = "0.4" libc = "0.2.146" libdnf-sys = { path = "rust/libdnf-sys", version = "0.1.0" } maplit = "1.0" memfd = "0.6.0" nix = "0.26.1" -openssl = "0.10.49" +openssl = "0.10.54" once_cell = "1.18.0" os-release = "0.1.0" -ostree-ext = "0.11.0" +ostree-ext = { git = "https://github.com/ostreedev/ostree-rs-ext.git", rev = "ea853c082c09594e1559e55b91d011994feb855b" } paste = "1.0" phf = { version = "0.11", features = ["macros"] } rand = "0.8.5" rayon = "1.6.0" -regex = "1.7" +regex = "1.8" reqwest = { version = "0.11", features = ["native-tls", "blocking", "gzip"] } rpmostree-client = { path = "rust/rpmostree-client", version = "0.1.0" } rust-ini = "0.19.0" -serde = { version = "1.0.163", features = ["derive"] } +serde = { version = "1.0.164", features = ["derive"] } serde_derive = "1.0.118" serde_json = "1.0.96" serde_yaml = "0.9.16" diff --git a/Makefile-rpm-ostree.am b/Makefile-rpm-ostree.am index 2ef84f8355..be80a6d7de 100644 --- a/Makefile-rpm-ostree.am +++ b/Makefile-rpm-ostree.am @@ -132,6 +132,7 @@ install-rpmostree-hook: install -m 0755 -t $(DESTDIR)$(bindir) rpm-ostree install -d -m 0755 $(ostreeextdir) ln -Tsr -f $(DESTDIR)$(bindir)/rpm-ostree $(ostreeextdir)/ostree-ima-sign + ln -Tsr -f $(DESTDIR)$(bindir)/rpm-ostree $(ostreeextdir)/ostree-provisional-repair ln -Tsr -f $(DESTDIR)$(bindir)/rpm-ostree $(ostreeextdir)/ostree-container INSTALL_EXEC_HOOKS += install-rpmostree-hook diff --git a/api-doc/Makefile.am b/api-doc/Makefile.am index 084dd766a5..12a1df8bae 100644 --- a/api-doc/Makefile.am +++ b/api-doc/Makefile.am @@ -78,7 +78,7 @@ content_files= \ overview.xml \ $(NULL) -# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded +# SGML files where gtk-doc abbreviations (#GtkWidget) are expanded # These files must be listed here *and* in content_files # e.g. expand_content_files=running.sgml expand_content_files= \ diff --git a/ci/test-container.sh b/ci/test-container.sh index 0a5a0ba3e2..8d9ab94fe2 100755 --- a/ci/test-container.sh +++ b/ci/test-container.sh @@ -58,8 +58,6 @@ versionid=$(. /usr/lib/os-release && echo $VERSION_ID) # Let's start by trying to install a bona fide module. # NOTE: If changing this also change the layering-modules test case $versionid in - 36) module=cri-o:1.23/default;; - 37) module=cri-o:1.24/default;; 38) module=cri-o:1.25/default;; *) assert_not_reached "Unsupported Fedora version: $versionid";; esac @@ -77,16 +75,8 @@ fi versionid=$(grep -E '^VERSION_ID=' /etc/os-release) versionid=${versionid:11} # trim off VERSION_ID= case $versionid in - 37) - url_suffix=2.14.0/3.fc37/x86_64/ignition-2.14.0-3.fc37.x86_64.rpm - # 2.14.0-4 - koji_url="https://koji.fedoraproject.org/koji/buildinfo?buildID=2013062" - koji_kernel_url="https://koji.fedoraproject.org/koji/buildinfo?buildID=2084352" - kver=6.0.7 - krev=301 - ;; 38) - url_suffix=2.15.0/2.fc38/x86_64/ignition-2.15.0-2.fc38.x86_64.rpm + url_suffix=2.15.0/4.fc37/x86_64/ignition-2.15.0-4.fc37.x86_64.rpm # 2.15.0-3 koji_url="https://koji.fedoraproject.org/koji/buildinfo?buildID=2158585" koji_kernel_url="https://koji.fedoraproject.org/koji/buildinfo?buildID=2174317" @@ -158,4 +148,12 @@ if ! grep -qe "error: No such file or directory" err.txt; then fatal "did not find expected error when skipping CLI wraps." fi +# test bootc cli call +ln -s /usr/bin/rpm-ostree /usr/bin/bootc +bootc --help > out.txt +if ! grep -qe "Deploy and upgrade via bootable container images" out.txt; then + cat out.txt + fatal "did not find expected bootc message when using sym link to rpm-ostree." +fi + echo ok diff --git a/configure.ac b/configure.ac index f9aface629..b51a529bd2 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ dnl dnl SEE RELEASE.md FOR INSTRUCTIONS ON HOW TO DO A RELEASE. dnl m4_define([year_version], [2023]) -m4_define([release_version], [4]) +m4_define([release_version], [5]) m4_define([package_version], [year_version.release_version]) AC_INIT([rpm-ostree], [package_version], [coreos@lists.fedoraproject.org]) AC_CONFIG_HEADER([config.h]) diff --git a/deny.toml b/deny.toml index b9b58f92cc..dccc9f7d23 100644 --- a/deny.toml +++ b/deny.toml @@ -9,4 +9,7 @@ private = { ignore = true } [sources] unknown-registry = "deny" unknown-git = "deny" -allow-git = [] \ No newline at end of file +allow-git = [ + "https://github.com/containers/bootc.git", + "https://github.com/ostreedev/ostree-rs-ext.git", +] diff --git a/docs/_config.yml b/docs/_config.yml index 006ac4bd2d..26bd9ccfdd 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -1,9 +1,12 @@ -title: coreos/rpm-ostree +# Template generated by https://github.com/coreos/repo-templates; do not edit downstream + +# To test documentation changes locally or using GitHub Pages, see: +# https://github.com/coreos/fedora-coreos-tracker/blob/main/docs/testing-project-documentation-changes.md + +title: rpm-ostree description: rpm-ostree documentation baseurl: "/rpm-ostree" url: "https://coreos.github.io" -# Comment above and use below for local development -# url: "http://localhost:4000" permalink: /:title/ markdown: kramdown kramdown: diff --git a/docs/container.md b/docs/container.md index ec5d4f09cb..20fac97a8d 100644 --- a/docs/container.md +++ b/docs/container.md @@ -28,10 +28,44 @@ For example, `rpm-ostree upgrade` will look for a new container version. You can also `rpm-ostree apply-live`, etc. It also does still work to do "client side" `rpm-ostree install` etc. +## URL format for ostree native containers + +Ostree understand the following URL formats to retrieve and optionally verify +the integrity of a container image or its content: + +- `ostree-unverified-image:registry:` or + `ostree-unverified-image:docker://`: Fetch a container image + without verify either the integrity of the container itself not its content. + The container image is usually fetched over HTTPS which still provides + integrity and confidentiality but not authenticity. + +- `ostree-unverified-registry:`: Shortcut for the above use case. + +- `ostree-remote-image::registry:` & + `ostree-remote-image::docker://`: Fetch a container + image and verify that the included ostree commit is correctly signed by a key + as configured locally in the specified ostree remote + (`/etc/ostree/remotes.d/.conf`). + +- `ostree-remote-registry::`: Shortcut for the above +use case. + +- `ostree-image-signed:registry:` & + `ostree-image-signed:docker://`: Fetch a container image and + verify that the container image is signed according to the policy set in + `/etc/containers/policy.json` (see + [containers-policy.json(5)](https://github.com/containers/image/blob/main/docs/containers-policy.json.5.md#policy-requirements)). + +ostree ([ostree-rs-ext](https://github.com/ostreedev/ostree-rs-ext)) uses +[skopeo](https://github.com/containers/skopeo) to fetch container images and +thus supports the transports as documented in +[containers-transports(5)](https://github.com/containers/image/blob/main/docs/containers-transports.5.md). + ## Registry authentication Today, the ostree stack will read `/etc/ostree/auth.json` and `/run/ostree/auth.json` -which are in the same format as documented by [man containers-auth.json](https://github.com/containers/image/blob/main/docs/containers-auth.json.5.md). +which are in the same format as documented by +[containers-auth.json(5)](https://github.com/containers/image/blob/main/docs/containers-auth.json.5.md). ## Using custom builds diff --git a/libdnf b/libdnf index 2362930d10..998efa8f41 160000 --- a/libdnf +++ b/libdnf @@ -1 +1 @@ -Subproject commit 2362930d10375a348bf2659db14b0ca4b911d4b7 +Subproject commit 998efa8f41188f9dc4b08b74086c2c3e2a38f73a diff --git a/libglnx b/libglnx index 07e3e49d3e..c02eb59916 160000 --- a/libglnx +++ b/libglnx @@ -1 +1 @@ -Subproject commit 07e3e49d3e47dfd4265ffb5495111439131715ca +Subproject commit c02eb5991695be11899fe0bdf6bd71ae2ff1ae21 diff --git a/man/rpm-ostree.xml b/man/rpm-ostree.xml index 1b530856f6..dcf7e1974c 100644 --- a/man/rpm-ostree.xml +++ b/man/rpm-ostree.xml @@ -328,6 +328,20 @@ Boston, MA 02111-1307, USA. + + search + + + + Takes one or more query terms as arguments. The packages are + searched within the enabled repositories in + /etc/yum.repos.d/. Packages can be + overlayed and removed using the install + and uninstall commands. + + + + rebase diff --git a/packaging/rpm-ostree.spec.in b/packaging/rpm-ostree.spec.in index 127e807281..67d2793762 100644 --- a/packaging/rpm-ostree.spec.in +++ b/packaging/rpm-ostree.spec.in @@ -3,9 +3,9 @@ Summary: Hybrid image/package system Name: rpm-ostree -Version: 2023.4 +Version: 2023.5 Release: 1%{?dist} -License: LGPLv2+ +License: LGPL-2.0-or-later URL: https://github.com/coreos/rpm-ostree # This tarball is generated via "cd packaging && make -f Makefile.dist-packaging dist-snapshot" # in the upstream git. It also contains vendored Rust sources. diff --git a/rpmostree-cxxrs.cxx b/rpmostree-cxxrs.cxx index 62a8ea164b..6dc42b329a 100644 --- a/rpmostree-cxxrs.cxx +++ b/rpmostree-cxxrs.cxx @@ -1293,6 +1293,7 @@ enum class SystemHostType : ::std::uint8_t; enum class BubblewrapMutability : ::std::uint8_t; struct Bubblewrap; struct ContainerImageState; +struct ExportedManifestDiff; enum class RefspecType : ::std::uint8_t; struct TempEtcGuard; struct FilesystemScriptPrep; @@ -1413,6 +1414,22 @@ struct ContainerImageState final }; #endif // CXXBRIDGE1_STRUCT_rpmostreecxx$ContainerImageState +#ifndef CXXBRIDGE1_STRUCT_rpmostreecxx$ExportedManifestDiff +#define CXXBRIDGE1_STRUCT_rpmostreecxx$ExportedManifestDiff +struct ExportedManifestDiff final +{ + bool initialized; + ::rust::u64 total; + ::rust::u64 total_size; + ::rust::u64 n_removed; + ::rust::u64 removed_size; + ::rust::u64 n_added; + ::rust::u64 added_size; + + using IsRelocatable = ::std::true_type; +}; +#endif // CXXBRIDGE1_STRUCT_rpmostreecxx$ExportedManifestDiff + #ifndef CXXBRIDGE1_ENUM_rpmostreecxx$RefspecType #define CXXBRIDGE1_ENUM_rpmostreecxx$RefspecType enum class RefspecType : ::std::uint8_t @@ -2064,6 +2081,10 @@ extern "C" const ::rpmostreecxx::OstreeRepo &repo, const ::rpmostreecxx::GCancellable &cancellable) noexcept; + ::rust::repr::PtrLen rpmostreecxx$cxxbridge1$compare_local_to_remote_container ( + const ::rpmostreecxx::OstreeRepo &repo, const ::rpmostreecxx::GCancellable &cancellable, + ::rust::Str imgref, ::rust::Box< ::rpmostreecxx::ExportedManifestDiff> *return$) noexcept; + ::rust::repr::PtrLen rpmostreecxx$cxxbridge1$query_container_image_commit ( const ::rpmostreecxx::OstreeRepo &repo, ::rust::Str c, ::rust::Box< ::rpmostreecxx::ContainerImageState> *return$) noexcept; @@ -3656,6 +3677,21 @@ container_prune (const ::rpmostreecxx::OstreeRepo &repo, } } +::rust::Box< ::rpmostreecxx::ExportedManifestDiff> +compare_local_to_remote_container (const ::rpmostreecxx::OstreeRepo &repo, + const ::rpmostreecxx::GCancellable &cancellable, + ::rust::Str imgref) +{ + ::rust::MaybeUninit< ::rust::Box< ::rpmostreecxx::ExportedManifestDiff> > return$; + ::rust::repr::PtrLen error$ = rpmostreecxx$cxxbridge1$compare_local_to_remote_container ( + repo, cancellable, imgref, &return$.value); + if (error$.ptr) + { + throw ::rust::impl< ::rust::Error>::error (error$); + } + return ::std::move (return$.value); +} + ::rust::Box< ::rpmostreecxx::ContainerImageState> query_container_image_commit (const ::rpmostreecxx::OstreeRepo &repo, ::rust::Str c) { @@ -5995,6 +6031,13 @@ extern "C" void cxxbridge1$box$rpmostreecxx$ContainerImageState$drop ( ::rust::Box< ::rpmostreecxx::ContainerImageState> *ptr) noexcept; + ::rpmostreecxx::ExportedManifestDiff * + cxxbridge1$box$rpmostreecxx$ExportedManifestDiff$alloc () noexcept; + void cxxbridge1$box$rpmostreecxx$ExportedManifestDiff$dealloc ( + ::rpmostreecxx::ExportedManifestDiff *) noexcept; + void cxxbridge1$box$rpmostreecxx$ExportedManifestDiff$drop ( + ::rust::Box< ::rpmostreecxx::ExportedManifestDiff> *ptr) noexcept; + ::rpmostreecxx::TempEtcGuard *cxxbridge1$box$rpmostreecxx$TempEtcGuard$alloc () noexcept; void cxxbridge1$box$rpmostreecxx$TempEtcGuard$dealloc (::rpmostreecxx::TempEtcGuard *) noexcept; void cxxbridge1$box$rpmostreecxx$TempEtcGuard$drop ( @@ -6335,6 +6378,25 @@ Box< ::rpmostreecxx::ContainerImageState>::drop () noexcept cxxbridge1$box$rpmostreecxx$ContainerImageState$drop (this); } template <> +::rpmostreecxx::ExportedManifestDiff * +Box< ::rpmostreecxx::ExportedManifestDiff>::allocation::alloc () noexcept +{ + return cxxbridge1$box$rpmostreecxx$ExportedManifestDiff$alloc (); +} +template <> +void +Box< ::rpmostreecxx::ExportedManifestDiff>::allocation::dealloc ( + ::rpmostreecxx::ExportedManifestDiff *ptr) noexcept +{ + cxxbridge1$box$rpmostreecxx$ExportedManifestDiff$dealloc (ptr); +} +template <> +void +Box< ::rpmostreecxx::ExportedManifestDiff>::drop () noexcept +{ + cxxbridge1$box$rpmostreecxx$ExportedManifestDiff$drop (this); +} +template <> ::rpmostreecxx::TempEtcGuard * Box< ::rpmostreecxx::TempEtcGuard>::allocation::alloc () noexcept { diff --git a/rpmostree-cxxrs.h b/rpmostree-cxxrs.h index dd2f59e89f..138ebc7680 100644 --- a/rpmostree-cxxrs.h +++ b/rpmostree-cxxrs.h @@ -1075,6 +1075,7 @@ enum class SystemHostType : ::std::uint8_t; enum class BubblewrapMutability : ::std::uint8_t; struct Bubblewrap; struct ContainerImageState; +struct ExportedManifestDiff; enum class RefspecType : ::std::uint8_t; struct TempEtcGuard; struct FilesystemScriptPrep; @@ -1195,6 +1196,22 @@ struct ContainerImageState final }; #endif // CXXBRIDGE1_STRUCT_rpmostreecxx$ContainerImageState +#ifndef CXXBRIDGE1_STRUCT_rpmostreecxx$ExportedManifestDiff +#define CXXBRIDGE1_STRUCT_rpmostreecxx$ExportedManifestDiff +struct ExportedManifestDiff final +{ + bool initialized; + ::rust::u64 total; + ::rust::u64 total_size; + ::rust::u64 n_removed; + ::rust::u64 removed_size; + ::rust::u64 n_added; + ::rust::u64 added_size; + + using IsRelocatable = ::std::true_type; +}; +#endif // CXXBRIDGE1_STRUCT_rpmostreecxx$ExportedManifestDiff + #ifndef CXXBRIDGE1_ENUM_rpmostreecxx$RefspecType #define CXXBRIDGE1_ENUM_rpmostreecxx$RefspecType enum class RefspecType : ::std::uint8_t @@ -1768,6 +1785,11 @@ pull_container (const ::rpmostreecxx::OstreeRepo &repo, void container_prune (const ::rpmostreecxx::OstreeRepo &repo, const ::rpmostreecxx::GCancellable &cancellable); +::rust::Box< ::rpmostreecxx::ExportedManifestDiff> +compare_local_to_remote_container (const ::rpmostreecxx::OstreeRepo &repo, + const ::rpmostreecxx::GCancellable &cancellable, + ::rust::Str imgref); + ::rust::Box< ::rpmostreecxx::ContainerImageState> query_container_image_commit (const ::rpmostreecxx::OstreeRepo &repo, ::rust::Str c); diff --git a/rust/libdnf-sys/Cargo.toml b/rust/libdnf-sys/Cargo.toml index 44a9f8b1aa..1f1b74672d 100644 --- a/rust/libdnf-sys/Cargo.toml +++ b/rust/libdnf-sys/Cargo.toml @@ -7,7 +7,7 @@ links = "dnf" publish = false [dependencies] -cxx = "1.0.95" +cxx = "1.0.101" [lib] name = "libdnf_sys" @@ -17,7 +17,7 @@ path = "lib.rs" cmake = "0.1.50" system-deps = "6.1" anyhow = "1.0" -cxx-build = "1.0.95" +cxx-build = "1.0.101" # This currently needs to duplicate the libraries from libdnf [package.metadata.system-deps] diff --git a/rust/rpmostree-client/Cargo.toml b/rust/rpmostree-client/Cargo.toml index a41e1b92d3..2886312870 100644 --- a/rust/rpmostree-client/Cargo.toml +++ b/rust/rpmostree-client/Cargo.toml @@ -12,6 +12,6 @@ publish = false [dependencies] anyhow = "1.0.69" -serde = { version = "1.0.163", features = ["derive"] } +serde = { version = "1.0.164", features = ["derive"] } serde_derive = "1.0.118" serde_json = "1.0.96" diff --git a/rust/src/builtins/scriptlet_intercept/groupadd.rs b/rust/src/builtins/scriptlet_intercept/groupadd.rs index 0b74a0a463..ef9e6dc393 100644 --- a/rust/src/builtins/scriptlet_intercept/groupadd.rs +++ b/rust/src/builtins/scriptlet_intercept/groupadd.rs @@ -46,7 +46,12 @@ fn cli_cmd() -> Command { Command::new(name) .bin_name(name) .about("create a new group") - .arg(Arg::new("force").short('f').long("force")) + .arg( + Arg::new("force") + .short('f') + .long("force") + .action(ArgAction::SetTrue), + ) .arg( Arg::new("gid") .short('g') diff --git a/rust/src/container.rs b/rust/src/container.rs index 6ca9605dbf..468ced8809 100644 --- a/rust/src/container.rs +++ b/rust/src/container.rs @@ -7,13 +7,14 @@ use std::num::NonZeroU32; use std::process::Command; use std::rc::Rc; -use anyhow::Result; +use anyhow::{Context, Result}; use camino::{Utf8Path, Utf8PathBuf}; use cap_std::fs::Dir; use cap_std_ext::cap_std; use cap_std_ext::prelude::*; use chrono::prelude::*; use clap::Parser; +use fn_error_context::context; use ostree::glib; use ostree_ext::chunking::ObjectMetaSized; use ostree_ext::container::{Config, ExportOpts, ImageReference}; @@ -425,7 +426,10 @@ pub fn container_encapsulate(args: Vec) -> CxxResult<()> { let package_structure = opt .previous_build_manifest .as_ref() - .map(|p| oci_spec::image::ImageManifest::from_file(&p).map_err(anyhow::Error::new)) + .map(|p| { + oci_spec::image::ImageManifest::from_file(&p) + .map_err(|e| anyhow::anyhow!("Failed to read previous manifest {p}: {e}")) + }) .transpose()?; let mut copy_meta_keys = opt.copy_meta_keys; @@ -483,6 +487,7 @@ struct UpdateFromRunningOpts { } // This reimplements https://github.com/ostreedev/ostree/pull/2691 basically +#[context("Finding encapsulated commits")] fn find_encapsulated_commits(repo: &Utf8Path) -> Result> { let objects = Dir::open_ambient_dir(&repo.join("objects"), cap_std::ambient_authority())?; let mut r = Vec::new(); @@ -550,7 +555,10 @@ pub(crate) fn deploy_from_self_entrypoint(args: Vec) -> CxxResult<()> { let encapsulated_commits = find_encapsulated_commits(src_repo_path)?; let commit = match encapsulated_commits.as_slice() { [] => return Err(format!("No encapsulated commit found in container").into()), - [c] => c.as_str(), + [c] => { + ostree::validate_checksum_string(&c)?; + c.as_str() + } o => return Err(format!("Found {} commit objects, expected just one", o.len()).into()), }; @@ -564,12 +572,14 @@ pub(crate) fn deploy_from_self_entrypoint(args: Vec) -> CxxResult<()> { opts.insert("refs", &&refs[..]); opts.insert("flags", &(flags.bits() as i32)); let options = opts.to_variant(); - target_repo.pull_with_options( - &format!("file://{src_repo_path}"), - &options, - None, - cancellable, - )?; + target_repo + .pull_with_options( + &format!("file://{src_repo_path}"), + &options, + None, + cancellable, + ) + .context("Pulling from embedded repo")?; } println!("Imported: {commit}"); diff --git a/rust/src/importer.rs b/rust/src/importer.rs index eb91ff23a1..f552bc64ca 100644 --- a/rust/src/importer.rs +++ b/rust/src/importer.rs @@ -346,16 +346,9 @@ fn tweak_imported_file_info(file_info: &FileInfo, ro_executables: bool) { #[context("Analyzing {}", path)] fn import_filter( path: &str, - file_info: &FileInfo, + _file_info: &FileInfo, skip_extraneous: bool, ) -> Result { - // Sanity check that RPM isn't using CPIO id fields. - let uid = file_info.attribute_uint32("unix::uid"); - let gid = file_info.attribute_uint32("unix::gid"); - if uid != 0 || gid != 0 { - bail!("Unexpected non-root owned path (marked as {}:{})", uid, gid); - } - // Skip some empty lock files, they are known to cause problems: // https://github.com/projectatomic/rpm-ostree/pull/1002 if path.starts_with("/usr/etc/selinux") && path.ends_with(".LOCK") { diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 43b3688521..a15ec5f704 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -188,6 +188,24 @@ pub mod ffi { pub version: String, } + #[derive(Debug)] + pub(crate) struct ExportedManifestDiff { + /// Check if the struct is initialized + pub initialized: bool, + /// The total number of packages in the next upgrade + pub total: u64, + /// The size of the total number of packages in the next upgrade + pub total_size: u64, + /// The total number of removed packages in the next upgrade + pub n_removed: u64, + /// The size of total number of removed packages in the next upgrade + pub removed_size: u64, + /// The total number of added packages in the next upgrade + pub n_added: u64, + /// The size of total number of added packages in the next upgrade + pub added_size: u64, + } + // sysroot_upgrade.rs extern "Rust" { fn pull_container( @@ -201,6 +219,11 @@ pub mod ffi { c: &str, ) -> Result>; fn purge_refspec(repo: &OstreeRepo, refspec: &str) -> Result<()>; + fn compare_local_to_remote_container( + repo: &OstreeRepo, + cancellable: &GCancellable, + imgref: &str, + ) -> Result>; } // core.rs diff --git a/rust/src/main.rs b/rust/src/main.rs index 9088c5f045..1439b9f2ff 100644 --- a/rust/src/main.rs +++ b/rust/src/main.rs @@ -50,10 +50,19 @@ async fn dispatch_ostree_ext(args: Vec) -> Result { Ok(0) } +/// Invoke the bootc CLI code. +async fn dispatch_bootc(args: Vec) -> Result { + bootc::cli::run_from_iter(args).await?; + Ok(0) +} + /// Dispatch multicall binary to relevant logic, based on callname from `argv[0]`. async fn dispatch_multicall(callname: String, args: Vec) -> Result { match callname.as_str() { - "ostree-container" | "ostree-ima-sign" => dispatch_ostree_ext(args).await, + "ostree-container" | "ostree-ima-sign" | "ostree-provisional-repair" => { + dispatch_ostree_ext(args).await + } + "bootc" => dispatch_bootc(args).await, _ => inner_async_main(args).await, // implicitly includes "rpm-ostree" } } diff --git a/rust/src/passwd.rs b/rust/src/passwd.rs index 9348f8627d..4bedf107bc 100644 --- a/rust/src/passwd.rs +++ b/rust/src/passwd.rs @@ -315,8 +315,8 @@ fn passwd_compose_prep_impl( rootfs.create_dir_with(dest, &db)?; // TODO(lucab): consider reworking these to avoid boolean results. - let found_passwd_data = data_from_json(rootfs, treefile, dest, "passwd")?; - let found_groups_data = data_from_json(rootfs, treefile, dest, "group")?; + let found_passwd_data = write_data_from_treefile(rootfs, treefile, dest, &PasswdKind::User)?; + let found_groups_data = write_data_from_treefile(rootfs, treefile, dest, &PasswdKind::Group)?; // We should error if we are getting passwd data from JSON and group from // previous commit, or vice versa, as that'll confuse everyone when it goes @@ -340,53 +340,110 @@ fn passwd_compose_prep_impl( Ok(()) } -fn data_from_json( +// PasswdKind includes 2 types: user and group. +#[derive(Debug)] +enum PasswdKind { + User, + Group, +} + +impl PasswdKind { + // Get user/group passwd file + fn passwd_file(&self) -> &'static str { + return match *self { + PasswdKind::User => "passwd", + PasswdKind::Group => "group", + }; + } + // Get user/group shadow file + fn shadow_file(&self) -> &'static str { + return match *self { + PasswdKind::User => "shadow", + PasswdKind::Group => "gshadow", + }; + } +} + +// This function writes the static passwd/group data from the treefile to the +// target root filesystem. +fn write_data_from_treefile( rootfs: &Dir, treefile: &mut Treefile, dest_path: &str, - target: &str, + target: &PasswdKind, ) -> Result { anyhow::ensure!(!dest_path.is_empty(), "missing destination path"); let append_unique_entries = match target { - "passwd" => passwd_append_unique, - "group" => group_append_unique, - x => anyhow::bail!("invalid merge target '{}'", x), + PasswdKind::User => passwd_append_unique, + PasswdKind::Group => group_append_unique, }; - let target_etc_filename = format!("{}{}", dest_path, target); + let passwd_name = target.passwd_file(); + let target_passwd_path = format!("{}{}", dest_path, passwd_name); // Migrate the check data from the specified file to /etc. - let mut src_file = if target == "passwd" { - let check_passwd_file = match treefile.parsed.get_check_passwd() { - CheckPasswd::File(cfg) => cfg, - _ => return Ok(false), - }; - treefile.externals.passwd_file_mut(check_passwd_file)? - } else if target == "group" { - let check_groups_file = match treefile.parsed.get_check_groups() { - CheckGroups::File(cfg) => cfg, - _ => return Ok(false), - }; - treefile.externals.group_file_mut(check_groups_file)? - } else { - unreachable!("impossible merge target '{}'", target); + let mut src_file = match target { + PasswdKind::User => { + let check_passwd_file = match treefile.parsed.get_check_passwd() { + CheckPasswd::File(cfg) => cfg, + _ => return Ok(false), + }; + treefile.externals.passwd_file_mut(check_passwd_file)? + } + PasswdKind::Group => { + let check_groups_file = match treefile.parsed.get_check_groups() { + CheckGroups::File(cfg) => cfg, + _ => return Ok(false), + }; + treefile.externals.group_file_mut(check_groups_file)? + } }; let mut seen_names = HashSet::new(); rootfs - .atomic_replace_with(&target_etc_filename, |dest_bufwr| -> Result<()> { + .atomic_replace_with(&target_passwd_path, |dest_bufwr| -> Result<()> { dest_bufwr .get_mut() .as_file_mut() .set_permissions(DEFAULT_PERMS.clone())?; let mut buf_rd = BufReader::new(&mut src_file); - append_unique_entries(&mut buf_rd, &mut seen_names, dest_bufwr) - .with_context(|| format!("failed to process '{}' content from JSON", &target))?; + append_unique_entries(&mut buf_rd, &mut seen_names, dest_bufwr).with_context(|| { + format!("failed to process '{}' content from JSON", &passwd_name) + })?; Ok(()) }) - .with_context(|| format!("failed to write /{}", &target_etc_filename))?; + .with_context(|| format!("failed to write /{}", &target_passwd_path))?; + // Regenerate etc/{,g}shadow to sync with etc/{passwd,group} + let db = rootfs.open(target_passwd_path).map(BufReader::new)?; + let shadow_name = target.shadow_file(); + let target_shadow_path = format!("{}{}", dest_path, shadow_name); + + match target { + PasswdKind::User => { + let entries = nameservice::passwd::parse_passwd_content(db)?; + rootfs + .atomic_replace_with(&target_shadow_path, |target_shadow| -> Result<()> { + for user in entries { + writeln!(target_shadow, "{}:*::0:99999:7:::", user.name)?; + } + Ok(()) + }) + .with_context(|| format!("Writing {target_shadow_path}"))?; + } + PasswdKind::Group => { + let entries = nameservice::group::parse_group_content(db)?; + rootfs + .atomic_replace_with(&target_shadow_path, |target_shadow| -> Result<()> { + for group in entries { + writeln!(target_shadow, "{}:::", group.name)?; + } + Ok(()) + }) + .with_context(|| format!("Writing {target_shadow_path}"))?; + } + } Ok(true) } diff --git a/rust/src/sysroot_upgrade.rs b/rust/src/sysroot_upgrade.rs index 8699156ea9..8f806a24ad 100644 --- a/rust/src/sysroot_upgrade.rs +++ b/rust/src/sysroot_upgrade.rs @@ -3,6 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT use crate::cxxrsutil::*; +use crate::ffi::ExportedManifestDiff; use crate::ffi::{output_message, ContainerImageState}; use anyhow::Result; use ostree::glib; @@ -56,12 +57,20 @@ async fn layer_progress_print(mut r: Receiver) { } } -fn default_container_pull_config() -> Result { +fn default_container_pull_config(imgref: &OstreeImageReference) -> Result { let mut cfg = ImageProxyConfig::default(); - let isolation_systemd = crate::utils::running_in_systemd().then(|| "rpm-ostree"); - let isolation_default = rustix::process::getuid().is_root().then(|| "nobody"); - let isolation_user = isolation_systemd.or(isolation_default); - ostree_container::merge_default_container_proxy_opts_with_isolation(&mut cfg, isolation_user)?; + if imgref.imgref.transport == ostree_container::Transport::ContainerStorage { + // Fetching from containers-storage, may require privileges to read files + ostree_container::merge_default_container_proxy_opts_with_isolation(&mut cfg, None)?; + } else { + let isolation_systemd = crate::utils::running_in_systemd().then(|| "rpm-ostree"); + let isolation_default = rustix::process::getuid().is_root().then(|| "nobody"); + let isolation_user = isolation_systemd.or(isolation_default); + ostree_container::merge_default_container_proxy_opts_with_isolation( + &mut cfg, + isolation_user, + )?; + } Ok(cfg) } @@ -70,7 +79,7 @@ async fn pull_container_async( imgref: &OstreeImageReference, ) -> Result { output_message(&format!("Pulling manifest: {}", &imgref)); - let config = default_container_pull_config()?; + let config = default_container_pull_config(imgref)?; let mut imp = ImageImporter::new(repo, imgref, config).await?; let layer_progress = imp.request_progress(); let prep = match imp.prepare().await? { @@ -191,3 +200,83 @@ pub(crate) fn purge_refspec(repo: &crate::FFIOstreeRepo, imgref: &str) -> CxxRes } Ok(()) } + +pub(crate) fn compare_local_to_remote_container( + repo: &crate::FFIOstreeRepo, + cancellable: &crate::FFIGCancellable, + imgref: &str, +) -> CxxResult> { + let repo = &repo.glib_reborrow(); + let cancellable = cancellable.glib_reborrow(); + let imgref = &OstreeImageReference::try_from(imgref)?; + let r = Handle::current().block_on(async { + crate::utils::run_with_cancellable( + async { get_container_manifest_diff(repo, imgref).await }, + &cancellable, + ) + .await + })?; + Ok(Box::new(r)) +} + +pub async fn get_container_manifest_diff( + repo: &ostree::Repo, + imgref: &OstreeImageReference, +) -> Result { + use ostree_ext::container::ManifestDiff; + let previous_state = + if let Some(r) = ostree_ext::container::store::query_image_ref(&repo, &imgref.imgref)? { + r + } else { + let manifest_diff = ExportedManifestDiff { + initialized: false, + total: 0, + total_size: 0, + n_removed: 0, + removed_size: 0, + n_added: 0, + added_size: 0, + }; + return Ok(manifest_diff); + }; + + let (manifest, _) = ostree_ext::container::fetch_manifest(&imgref).await?; + let diff = ManifestDiff::new(&previous_state.manifest, &manifest); + + let manifest_diff = ExportedManifestDiff { + initialized: true, + total: diff.total, + total_size: diff.total_size, + n_removed: diff.n_removed, + removed_size: diff.removed_size, + n_added: diff.n_added, + added_size: diff.added_size, + }; + + Ok(manifest_diff) +} + +#[test] +fn test_container_manifest_diff() -> Result<()> { + use ostree_ext::container::ManifestDiff; + use ostree_ext::oci_spec::image::ImageManifest; + let a: ImageManifest = serde_json::from_str(include_str!("../test/manifest1.json")).unwrap(); + let b: ImageManifest = serde_json::from_str(include_str!("../test/manifest2.json")).unwrap(); + let diff = ManifestDiff::new(&a, &b); + + let cmp_total = diff.total; + let cmp_total_size = diff.total_size; + let cmp_removed = diff.n_removed; + let cmp_removed_size = diff.removed_size; + let cmp_added = diff.n_added; + let cmp_added_size = diff.added_size; + + assert_eq!(cmp_total, 51 as u64); + assert_eq!(cmp_total_size, 697035490 as u64); + assert_eq!(cmp_removed, 4 as u64); + assert_eq!(cmp_removed_size, 170473141 as u64); + assert_eq!(cmp_added, 4 as u64); + assert_eq!(cmp_added_size, 170472856 as u64); + + Ok(()) +} diff --git a/rust/test/manifest1.json b/rust/test/manifest1.json new file mode 100644 index 0000000000..c9528d6d5b --- /dev/null +++ b/rust/test/manifest1.json @@ -0,0 +1 @@ +{"schemaVersion":2,"config":{"mediaType":"application/vnd.oci.image.config.v1+json","digest":"sha256:f3b50d0849a19894aa27ca2346a78efdacf2c56bdc2a3493672d2a819990fedf","size":9301},"layers":[{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:75f4abe8518ec55cb8bf0d358a737084f38e2c030a28651d698c0b7569d680a6","size":1387849},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:777cb841d2803f775a36fba62bcbfe84b2a1e0abc27cf995961b63c3d218a410","size":48676116},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:1179dc1e2994ec0466787ec43967db9016b4b93c602bb9675d7fe4c0993366ba","size":124705297},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:74555b3730c4c0f77529ead433db58e038070666b93a5cc0da262d7b8debff0e","size":38743650},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:0ff8b1fdd38e5cfb6390024de23ba4b947cd872055f62e70f2c21dad5c928925","size":77161948},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:76b83eea62b7b93200a056b5e0201ef486c67f1eeebcf2c7678ced4d614cece2","size":21970157},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:d85c742f69904cb8dbf98abca4724d364d91792fcf8b5f5634ab36dda162bfc4","size":59797135},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:167e5df36d0fcbed876ca90c1ed1e6c79b5e2bdaba5eae74ab86444654b19eff","size":49410348},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:b34384ba76fa1e335cc8d75522508d977854f2b423f8aceb50ca6dfc2f609a99","size":21714783},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:7bf2d65ebf222ee10115284abf6909b1a3da0f3bd6d8d849e30723636b7145cb","size":15264848},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:a75bbf55d8de4dbd54e429e16fbd46688717faf4ea823c94676529cc2525fd5f","size":14373701},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:cf728677fa8c84bfcfd71e17953062421538d492d7fbfdd0dbce8eb1e5f6eec3","size":8400473},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:caff60c1ef085fb500c94230ccab9338e531578635070230b1413b439fd53f8f","size":6914489},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:65ca8f9bddaa720b74c5a7401bf273e93eba6b3b855a62422a8258373e0b1ae0","size":8294965},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:387bab4fcb713e9691617a645b6af2b7ad29fe5e009b0b0d3215645ef315481c","size":6600369},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:f63dcde5a664dad3eb3321bbcf2913d9644d16561a67c86ab61d814c1462583d","size":16869027},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:8bcd90242651342fbd2ed5ca3e60d03de90fdd28c3a9f634329f6e1c21c79718","size":5735283},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:cb65c21a0659b5b826881280556995a7ca4818c2b9b7a89e31d816a996fa8640","size":4528663},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:5187f51b62f4a2e82198a75afcc623a0323d4804fa7848e2e0acb30d77b8d9ab","size":5266030},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:bfef79d6d35378fba9093083ff6bd7b5ed9f443f87517785e6ff134dc8d08c6a","size":4316135},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:1cf332fd50b382af7941d6416994f270c894e9d60fb5c6cecf25de887673bbcb","size":3914655},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:e0d80be6e71bfae398f06f7a7e3b224290f3dde7544c8413f922934abeb1f599","size":2441858},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:48ff87e7a7af41d7139c5230e2e939aa97cafb1f62a114825bda5f5904e04a0e","size":3818782},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:8bcc652ccaa27638bd5bd2d7188053f1736586afbae87b3952e9211c773e3563","size":3885971},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:d83d9388b8c8c1e7c97b6b18f5107b74354700ebce9da161ccb73156a2c54a2e","size":3442642},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:efc465ae44a18ee395e542eb97c8d1fc21bf9d5fb49244ba4738e9bf48bfd3dc","size":3066348},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:c5c471cce08aa9cc7d96884a9e1981b7bb67ee43524af47533f50a8ddde7a83d","size":909923},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:8956cd951abc481ba364cf8ef5deca7cc9185b59ed95ae40b52e42afdc271d8e","size":3553645},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:5b0963a6c89d595b5c4786e2f3ce0bc168a262efab74dfce3d7c8d1063482c60","size":1495301},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:bf2df295da2716291f9dd4707158bca218b4a7920965955a4808b824c1bee2b6","size":3063142},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:19b2ea8d63794b8249960d581216ae1ccb80f8cfe518ff8dd1f12d65d19527a5","size":8109718},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:420636df561ccc835ef9665f41d4bc91c5f00614a61dca266af2bcd7bee2cc25","size":3003935},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:5ae67caf0978d82848d47ff932eee83a1e5d2581382c9c47335f69c9d7acc180","size":2468557},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:4f4b8bb8463dc74bb7f32eee78d02b71f61a322967b6d6cbb29829d262376f74","size":2427605},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:69373f86b83e6e5a962de07f40ff780a031b42d2568ffbb8b3c36de42cc90dec","size":2991782},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:2d05c2f993f9761946701da37f45fc573a2db8467f92b3f0d356f5f7adaf229e","size":3085765},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:41925843e5c965165bedc9c8124b96038f08a89c95ba94603a5f782dc813f0a8","size":2724309},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:a8c39f2998073e0e8b55fb88ccd68d2621a0fb6e31a528fd4790a1c90f8508a9","size":2512079},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:b905f801d092faba0c155597dd1303fa8c0540116af59c111ed7744e486ed63b","size":2341122},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:4f46b58b37828fa71fa5d7417a8ca7a62761cc6a72eb1592943572fc2446b054","size":2759344},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:3fbae92ecc64cf253b643a0e75b56514dc694451f163b47fb4e15af373238e10","size":2539288},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:744dd4a3ec521668942661cf1f184eb8f07f44025ce1aa35d5072ad9d72946fe","size":2415870},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:6c74c0a05a36bddabef1fdfae365ff87a9c5dd1ec7345d9e20f7f8ab04b39fc6","size":2145078},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:910ff6f93303ebedde3459f599b06d7b70d8f0674e3fe1d6623e3af809245cc4","size":5098511},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:2752e2f62f38fea3a390f111d673d2529dbf929f6c67ec7ef4359731d1a7edd8","size":1051999},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:5065c3aac5fcc3c1bde50a19d776974353301f269a936dd2933a67711af3b703","size":2713694},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:8bf6993eea50bbd8b448e6fd719f83c82d1d40b623f2c415f7727e766587ea83","size":1686714},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:630221744f0f9632f4f34f74241e65f79e78f938100266a119113af1ce10a1c5","size":2061581},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:e7e2eae322bca0ffa01bb2cae72288507bef1a11ad51f99d0a4faba1b1e000b9","size":2079706},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:bb6374635385b0c2539c284b137d831bd45fbe64b5e49aee8ad92d14c156a41b","size":3142398},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:40493ecd0f9ab499a2bec715415c3a98774ea6d1c9c01eb30a6b56793204a02d","size":69953187}]} diff --git a/rust/test/manifest2.json b/rust/test/manifest2.json new file mode 100644 index 0000000000..76b1b1bd59 --- /dev/null +++ b/rust/test/manifest2.json @@ -0,0 +1 @@ +{"schemaVersion":2,"config":{"mediaType":"application/vnd.oci.image.config.v1+json","digest":"sha256:ca0f7e342503b45a1110aba49177e386242e9192ab1742a95998b6b99c2a0150","size":9301},"layers":[{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:bca674ffe2ebe92b9e952bc807b9f1cd0d559c057e95ac81f3bae12a9b96b53e","size":1387854},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:777cb841d2803f775a36fba62bcbfe84b2a1e0abc27cf995961b63c3d218a410","size":48676116},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:1179dc1e2994ec0466787ec43967db9016b4b93c602bb9675d7fe4c0993366ba","size":124705297},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:74555b3730c4c0f77529ead433db58e038070666b93a5cc0da262d7b8debff0e","size":38743650},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:0b5d930ffc92d444b0a7b39beed322945a3038603fbe2a56415a6d02d598df1f","size":77162517},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:8d12d20c2d1c8f05c533a2a1b27a457f25add8ad38382523660c4093f180887b","size":21970100},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:d85c742f69904cb8dbf98abca4724d364d91792fcf8b5f5634ab36dda162bfc4","size":59797135},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:167e5df36d0fcbed876ca90c1ed1e6c79b5e2bdaba5eae74ab86444654b19eff","size":49410348},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:b34384ba76fa1e335cc8d75522508d977854f2b423f8aceb50ca6dfc2f609a99","size":21714783},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:7bf2d65ebf222ee10115284abf6909b1a3da0f3bd6d8d849e30723636b7145cb","size":15264848},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:a75bbf55d8de4dbd54e429e16fbd46688717faf4ea823c94676529cc2525fd5f","size":14373701},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:cf728677fa8c84bfcfd71e17953062421538d492d7fbfdd0dbce8eb1e5f6eec3","size":8400473},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:caff60c1ef085fb500c94230ccab9338e531578635070230b1413b439fd53f8f","size":6914489},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:65ca8f9bddaa720b74c5a7401bf273e93eba6b3b855a62422a8258373e0b1ae0","size":8294965},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:387bab4fcb713e9691617a645b6af2b7ad29fe5e009b0b0d3215645ef315481c","size":6600369},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:f63dcde5a664dad3eb3321bbcf2913d9644d16561a67c86ab61d814c1462583d","size":16869027},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:8bcd90242651342fbd2ed5ca3e60d03de90fdd28c3a9f634329f6e1c21c79718","size":5735283},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:cb65c21a0659b5b826881280556995a7ca4818c2b9b7a89e31d816a996fa8640","size":4528663},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:5187f51b62f4a2e82198a75afcc623a0323d4804fa7848e2e0acb30d77b8d9ab","size":5266030},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:bfef79d6d35378fba9093083ff6bd7b5ed9f443f87517785e6ff134dc8d08c6a","size":4316135},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:1cf332fd50b382af7941d6416994f270c894e9d60fb5c6cecf25de887673bbcb","size":3914655},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:e0d80be6e71bfae398f06f7a7e3b224290f3dde7544c8413f922934abeb1f599","size":2441858},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:48ff87e7a7af41d7139c5230e2e939aa97cafb1f62a114825bda5f5904e04a0e","size":3818782},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:8bcc652ccaa27638bd5bd2d7188053f1736586afbae87b3952e9211c773e3563","size":3885971},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:d83d9388b8c8c1e7c97b6b18f5107b74354700ebce9da161ccb73156a2c54a2e","size":3442642},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:efc465ae44a18ee395e542eb97c8d1fc21bf9d5fb49244ba4738e9bf48bfd3dc","size":3066348},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:c5c471cce08aa9cc7d96884a9e1981b7bb67ee43524af47533f50a8ddde7a83d","size":909923},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:8956cd951abc481ba364cf8ef5deca7cc9185b59ed95ae40b52e42afdc271d8e","size":3553645},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:5b0963a6c89d595b5c4786e2f3ce0bc168a262efab74dfce3d7c8d1063482c60","size":1495301},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:bf2df295da2716291f9dd4707158bca218b4a7920965955a4808b824c1bee2b6","size":3063142},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:19b2ea8d63794b8249960d581216ae1ccb80f8cfe518ff8dd1f12d65d19527a5","size":8109718},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:420636df561ccc835ef9665f41d4bc91c5f00614a61dca266af2bcd7bee2cc25","size":3003935},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:5ae67caf0978d82848d47ff932eee83a1e5d2581382c9c47335f69c9d7acc180","size":2468557},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:4f4b8bb8463dc74bb7f32eee78d02b71f61a322967b6d6cbb29829d262376f74","size":2427605},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:69373f86b83e6e5a962de07f40ff780a031b42d2568ffbb8b3c36de42cc90dec","size":2991782},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:2d05c2f993f9761946701da37f45fc573a2db8467f92b3f0d356f5f7adaf229e","size":3085765},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:41925843e5c965165bedc9c8124b96038f08a89c95ba94603a5f782dc813f0a8","size":2724309},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:a8c39f2998073e0e8b55fb88ccd68d2621a0fb6e31a528fd4790a1c90f8508a9","size":2512079},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:b905f801d092faba0c155597dd1303fa8c0540116af59c111ed7744e486ed63b","size":2341122},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:4f46b58b37828fa71fa5d7417a8ca7a62761cc6a72eb1592943572fc2446b054","size":2759344},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:3fbae92ecc64cf253b643a0e75b56514dc694451f163b47fb4e15af373238e10","size":2539288},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:744dd4a3ec521668942661cf1f184eb8f07f44025ce1aa35d5072ad9d72946fe","size":2415870},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:6c74c0a05a36bddabef1fdfae365ff87a9c5dd1ec7345d9e20f7f8ab04b39fc6","size":2145078},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:910ff6f93303ebedde3459f599b06d7b70d8f0674e3fe1d6623e3af809245cc4","size":5098511},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:2752e2f62f38fea3a390f111d673d2529dbf929f6c67ec7ef4359731d1a7edd8","size":1051999},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:5065c3aac5fcc3c1bde50a19d776974353301f269a936dd2933a67711af3b703","size":2713694},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:8bf6993eea50bbd8b448e6fd719f83c82d1d40b623f2c415f7727e766587ea83","size":1686714},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:630221744f0f9632f4f34f74241e65f79e78f938100266a119113af1ce10a1c5","size":2061581},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:e7e2eae322bca0ffa01bb2cae72288507bef1a11ad51f99d0a4faba1b1e000b9","size":2079706},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:bb6374635385b0c2539c284b137d831bd45fbe64b5e49aee8ad92d14c156a41b","size":3142398},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:cb9b8a4ac4a8df62df79e6f0348a14b3ec239816d42985631c88e76d4e3ff815","size":69952385}]} diff --git a/src/app/libmain.cxx b/src/app/libmain.cxx index 60059238eb..497bef878b 100644 --- a/src/app/libmain.cxx +++ b/src/app/libmain.cxx @@ -73,6 +73,8 @@ static RpmOstreeCommand commands[] = { "Overlay additional packages", rpmostree_builtin_install }, { "uninstall", static_cast (RPM_OSTREE_BUILTIN_FLAG_CONTAINER_CAPABLE), "Remove overlayed additional packages", rpmostree_builtin_uninstall }, + { "search", static_cast (RPM_OSTREE_BUILTIN_FLAG_CONTAINER_CAPABLE), + "Search for packages", rpmostree_builtin_search }, { "override", static_cast (RPM_OSTREE_BUILTIN_FLAG_LOCAL_CMD), "Manage base package overrides", rpmostree_builtin_override }, { "reset", static_cast (RPM_OSTREE_BUILTIN_FLAG_SUPPORTS_PKG_INSTALLS), @@ -154,6 +156,14 @@ static GOptionEntry pkg_entries[] "Remove overlayed additional package", "PKG" }, { NULL } }; +static int +cmp_by_name (const void *a, const void *b) +{ + struct RpmOstreeCommand *command_a = (RpmOstreeCommand *)a; + struct RpmOstreeCommand *command_b = (RpmOstreeCommand *)b; + return strcmp (command_a->name, command_b->name); +} + static GOptionContext * option_context_new_with_commands (RpmOstreeCommandInvocation *invocation, RpmOstreeCommand *commands) @@ -171,6 +181,13 @@ option_context_new_with_commands (RpmOstreeCommandInvocation *invocation, else /* top level */ g_string_append (summary, "Builtin Commands:"); + int command_count = 0; + for (RpmOstreeCommand *command = commands; command->name != NULL; command++) + { + command_count++; + } + + qsort (commands, command_count, sizeof (RpmOstreeCommand), cmp_by_name); for (RpmOstreeCommand *command = commands; command->name != NULL; command++) { gboolean hidden = (command->flags & RPM_OSTREE_BUILTIN_FLAG_HIDDEN) > 0; diff --git a/src/app/rpmostree-builtins.h b/src/app/rpmostree-builtins.h index 43ef9ca6a8..877bdd34e0 100644 --- a/src/app/rpmostree-builtins.h +++ b/src/app/rpmostree-builtins.h @@ -50,6 +50,7 @@ BUILTINPROTO (internals); BUILTINPROTO (container); BUILTINPROTO (install); BUILTINPROTO (uninstall); +BUILTINPROTO (search); BUILTINPROTO (override); BUILTINPROTO (kargs); BUILTINPROTO (reset); diff --git a/src/app/rpmostree-clientlib.cxx b/src/app/rpmostree-clientlib.cxx index 65aa33cf93..a04fe39e67 100644 --- a/src/app/rpmostree-clientlib.cxx +++ b/src/app/rpmostree-clientlib.cxx @@ -1004,6 +1004,7 @@ rpmostree_update_deployment ( const char *local_repo_remote, const char *treefile, GVariant *options, char **out_transaction_address, GCancellable *cancellable, GError **error) { + GLNX_AUTO_PREFIX_ERROR ("Updating deployment", error); g_autoptr (GVariant) modifiers = NULL; glnx_unref_object GUnixFDList *fd_list = NULL; if (!get_modifiers_variant (set_refspec, set_revision, install_pkgs, install_fileoverride_pkgs, @@ -1243,6 +1244,82 @@ rpmostree_print_diff_advisories (GVariant *rpm_diff, GVariant *advisories, gbool return TRUE; } +/* print "manifest-diff" */ +gboolean +rpmostree_print_manifest_diff (GVariant *manifest_diff, guint maxkeylen, GError **error) +{ + int total_str = 0; + int total_size_str = 0; + int total_removed_str = 0; + int removed_size_str = 0; + int total_added_str = 0; + int added_size_str = 0; + + g_auto (GVariantDict) manifest_diff_dict; + g_variant_dict_init (&manifest_diff_dict, manifest_diff); + + g_autoptr (GVariant) total + = g_variant_dict_lookup_value (&manifest_diff_dict, "total", G_VARIANT_TYPE ("t")); + if (!total) + return FALSE; + + g_variant_get (total, "t", &total_str); + printf (" %*s%s %d", maxkeylen, "Total layers", strlen ("Total layers") ? ":" : " ", total_str); + printf ("\n"); + + g_autoptr (GVariant) total_size + = g_variant_dict_lookup_value (&manifest_diff_dict, "total_size", G_VARIANT_TYPE ("t")); + if (!total_size) + return FALSE; + + g_variant_get (total_size, "t", &total_size_str); + printf (" %*s%s %s", maxkeylen, "Size", strlen ("Size") ? ":" : " ", + g_format_size (total_size_str)); + printf ("\n"); + + g_autoptr (GVariant) total_removed + = g_variant_dict_lookup_value (&manifest_diff_dict, "total_removed", G_VARIANT_TYPE ("t")); + if (!total_removed) + return FALSE; + + g_variant_get (total_removed, "t", &total_removed_str); + printf (" %*s%s %d", maxkeylen, "Removed layers", strlen ("Removed layers") ? ":" : " ", + total_removed_str); + printf ("\n"); + + g_autoptr (GVariant) removed_size + = g_variant_dict_lookup_value (&manifest_diff_dict, "removed_size", G_VARIANT_TYPE ("t")); + if (!removed_size) + return FALSE; + + g_variant_get (removed_size, "t", &removed_size_str); + printf (" %*s%s %s", maxkeylen, "Size", strlen ("Size") ? ":" : " ", + g_format_size (removed_size_str)); + printf ("\n"); + + g_autoptr (GVariant) total_added + = g_variant_dict_lookup_value (&manifest_diff_dict, "total_added", G_VARIANT_TYPE ("t")); + if (!total_added) + return FALSE; + + g_variant_get (total_added, "t", &total_added_str); + printf (" %*s%s %d", maxkeylen, "Added layers", strlen ("Added layers") ? ":" : " ", + total_added_str); + printf ("\n"); + + g_autoptr (GVariant) added_size + = g_variant_dict_lookup_value (&manifest_diff_dict, "added_size", G_VARIANT_TYPE ("t")); + if (!added_size) + return FALSE; + + g_variant_get (added_size, "t", &added_size_str); + printf (" %*s%s %s", maxkeylen, "Size", strlen ("Size") ? ":" : " ", + g_format_size (added_size_str)); + printf ("\n"); + + return TRUE; +} + /* this is used by both `status` and `upgrade --check/--preview` */ gboolean rpmostree_print_cached_update (GVariant *cached_update, gboolean verbose, @@ -1285,6 +1362,9 @@ rpmostree_print_cached_update (GVariant *cached_update, gboolean verbose, g_autoptr (GVariant) rpm_diff = g_variant_dict_lookup_value (&dict, "rpm-diff", G_VARIANT_TYPE ("a{sv}")); + g_autoptr (GVariant) manifest_diff + = g_variant_dict_lookup_value (&dict, "manifest-diff", G_VARIANT_TYPE ("a{sv}")); + g_autoptr (GVariant) advisories = g_variant_dict_lookup_value (&dict, "advisories", G_VARIANT_TYPE ("a(suuasa{sv})")); @@ -1307,6 +1387,9 @@ rpmostree_print_cached_update (GVariant *cached_update, gboolean verbose, max_key_len, error)) return FALSE; + if (!rpmostree_print_manifest_diff (manifest_diff, max_key_len, error)) + return FALSE; + return TRUE; } diff --git a/src/app/rpmostree-clientlib.h b/src/app/rpmostree-clientlib.h index dd4f22c4c8..a47e672d62 100644 --- a/src/app/rpmostree-clientlib.h +++ b/src/app/rpmostree-clientlib.h @@ -111,6 +111,8 @@ gboolean rpmostree_print_diff_advisories (GVariant *rpm_diff, GVariant *advisori gboolean verbose, gboolean verbose_advisories, guint max_key_len, GError **error); +gboolean rpmostree_print_manifest_diff (GVariant *manifest_diff, guint maxkeylen, GError **error); + gboolean rpmostree_print_cached_update (GVariant *cached_update, gboolean verbose, gboolean verbose_advisories, GCancellable *cancellable, GError **error); diff --git a/src/app/rpmostree-pkg-builtins.cxx b/src/app/rpmostree-pkg-builtins.cxx index f2c26730d0..1ca3564c83 100644 --- a/src/app/rpmostree-pkg-builtins.cxx +++ b/src/app/rpmostree-pkg-builtins.cxx @@ -31,6 +31,8 @@ #include +#include + static char *opt_osname; static gboolean opt_reboot; static gboolean opt_dry_run; @@ -310,3 +312,102 @@ rpmostree_builtin_uninstall (int argc, char **argv, RpmOstreeCommandInvocation * return pkg_change (invocation, sysroot_proxy, FALSE, (const char *const *)opt_install, (const char *const *)argv, cancellable, error); } + +struct cstrless +{ + bool + operator() (const gchar *a, const gchar *b) const + { + return strcmp (a, b) < 0; + } +}; + +gboolean +rpmostree_builtin_search (int argc, char **argv, RpmOstreeCommandInvocation *invocation, + GCancellable *cancellable, GError **error) +{ + GOptionContext *context; + glnx_unref_object RPMOSTreeSysroot *sysroot_proxy = NULL; + + context = g_option_context_new ("PACKAGE [PACKAGE...]"); + g_option_context_add_main_entries (context, install_option_entry, NULL); + g_option_context_add_main_entries (context, uninstall_option_entry, NULL); + + if (!rpmostree_option_context_parse (context, option_entries, &argc, &argv, invocation, + cancellable, NULL, NULL, &sysroot_proxy, error)) + return FALSE; + + if (argc < 2) + { + rpmostree_usage_error (context, "At least one PACKAGE must be specified", error); + return FALSE; + } + + glnx_unref_object RPMOSTreeOS *os_proxy = NULL; + + if (!rpmostree_load_os_proxy (sysroot_proxy, opt_osname, cancellable, &os_proxy, error)) + return FALSE; + + g_autoptr (GPtrArray) arg_names = g_ptr_array_new (); + for (guint i = 1; i < argc; i++) + { + g_ptr_array_add (arg_names, (char *)argv[i]); + } + g_ptr_array_add (arg_names, NULL); + + g_autoptr (GVariant) out_packages = NULL; + + if (!rpmostree_os_call_search_sync (os_proxy, (const char *const *)arg_names->pdata, + &out_packages, cancellable, error)) + return FALSE; + + g_autoptr (GVariantIter) iter1 = NULL; + g_variant_get (out_packages, "aa{sv}", &iter1); + + g_autoptr (GVariantIter) iter2 = NULL; + std::set query_set; + + while (g_variant_iter_loop (iter1, "a{sv}", &iter2)) + { + const gchar *key; + const gchar *name; + const gchar *summary; + const gchar *query; + const gchar *match_group = ""; + + g_autoptr (GVariant) value = NULL; + + while (g_variant_iter_loop (iter2, "{sv}", &key, &value)) + { + if (strcmp (key, "key") == 0) + g_variant_get (value, "s", &query); + else if (strcmp (key, "name") == 0) + g_variant_get (value, "s", &name); + else if (strcmp (key, "summary") == 0) + g_variant_get (value, "s", &summary); + } + + if (!query_set.count (query)) + { + query_set.insert (query); + + if (strcmp (query, "match_group_a") == 0) + match_group = "Summary & Name"; + else if (strcmp (query, "match_group_b") == 0) + match_group = "Name"; + else if (strcmp (query, "match_group_c") == 0) + match_group = "Summary"; + + g_print ("\n===== %s Matched =====\n", match_group); + } + + g_print ("%s : %s\n", name, summary); + } + + if (query_set.size () == 0) + { + g_print ("No matches found.\n"); + } + + return TRUE; +} diff --git a/src/daemon/org.projectatomic.rpmostree1.xml b/src/daemon/org.projectatomic.rpmostree1.xml index b11ff5dfd2..7765b3fe54 100644 --- a/src/daemon/org.projectatomic.rpmostree1.xml +++ b/src/daemon/org.projectatomic.rpmostree1.xml @@ -477,6 +477,12 @@ + + + + + + diff --git a/src/daemon/rpm-ostreed.service b/src/daemon/rpm-ostreed.service index 8d1ef69cba..406ead652f 100644 --- a/src/daemon/rpm-ostreed.service +++ b/src/daemon/rpm-ostreed.service @@ -20,10 +20,6 @@ MountFlags=slave # and have a system rpm-ostreed-transaction.service that runs privileged # but as a subprocess. ProtectHome=true -# Explicitly list paths here which we should never access. The initial -# entry here ensures that the skopeo process we fork won't interact with -# application containers. -BindReadOnlyPaths=-/var/lib/containers NotifyAccess=main # Significantly bump this timeout from the default because # we do a lot of stuff on daemon startup. diff --git a/src/daemon/rpmostree-sysroot-upgrader.cxx b/src/daemon/rpmostree-sysroot-upgrader.cxx index 2beb3aee3b..d533c82f78 100644 --- a/src/daemon/rpmostree-sysroot-upgrader.cxx +++ b/src/daemon/rpmostree-sysroot-upgrader.cxx @@ -434,12 +434,19 @@ rpmostree_sysroot_upgrader_pull_base (RpmOstreeSysrootUpgrader *self, const char return glnx_throw (error, "Specifying commit overrides for container-image-reference " "type refspecs is not supported"); if (check) - return glnx_throw (error, "Cannot currently check for updates without downloading"); + { + *out_changed = FALSE; + return TRUE; + } + else + { + CXX_TRY_VAR ( + import, + rpmostreecxx::pull_container (*self->repo, *cancellable, r.refspec.c_str ()), + error); - CXX_TRY_VAR (import, - rpmostreecxx::pull_container (*self->repo, *cancellable, r.refspec.c_str ()), - error); - new_base_rev = g_strdup (import->merge_commit.c_str ()); + new_base_rev = g_strdup (import->merge_commit.c_str ()); + } break; } case rpmostreecxx::RefspecType::Checksum: diff --git a/src/daemon/rpmostreed-deployment-utils.cxx b/src/daemon/rpmostreed-deployment-utils.cxx index 4848050942..2c99950caf 100644 --- a/src/daemon/rpmostreed-deployment-utils.cxx +++ b/src/daemon/rpmostreed-deployment-utils.cxx @@ -399,6 +399,46 @@ rpm_diff_clear (RpmDiff *diff) G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC (RpmDiff, rpm_diff_clear); +typedef struct +{ + gboolean initialized; + GVariant *total; + GVariant *total_size; + GVariant *total_removed; + GVariant *removed_size; + GVariant *total_added; + GVariant *added_size; +} ManifestDiff; + +static void +manifest_diff_init (ManifestDiff *diff) +{ + g_assert (!diff->initialized); + diff->total = g_variant_new ("t", G_GUINT64_CONSTANT (0)); + diff->total_size = g_variant_new ("t", G_GUINT64_CONSTANT (0)); + diff->total_removed = g_variant_new ("t", G_GUINT64_CONSTANT (0)); + diff->removed_size = g_variant_new ("t", G_GUINT64_CONSTANT (0)); + diff->total_added = g_variant_new ("t", G_GUINT64_CONSTANT (0)); + diff->added_size = g_variant_new ("t", G_GUINT64_CONSTANT (0)); + diff->initialized = TRUE; +} + +static void +manifest_diff_clear (ManifestDiff *diff) +{ + if (!diff->initialized) + return; + g_variant_ref (diff->total); + g_variant_ref (diff->total_size); + g_variant_ref (diff->total_removed); + g_variant_ref (diff->removed_size); + g_variant_ref (diff->total_added); + g_variant_ref (diff->added_size); + diff->initialized = FALSE; +} + +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC (ManifestDiff, manifest_diff_clear); + static GVariant * single_pkg_variant_new (RpmOstreePkgTypes type, RpmOstreePackage *pkg) { @@ -474,6 +514,32 @@ rpm_diff_add_db_diff (RpmDiff *diff, OstreeRepo *repo, RpmOstreePkgTypes type, return TRUE; } +static gboolean +manifest_diff_add_db_diff (ManifestDiff *diff, rpmostreecxx::ExportedManifestDiff manifest_diff, + GCancellable *cancellable, GError **error) +{ + if (manifest_diff.initialized) + { + guint64 total_converted = manifest_diff.total; + guint64 total_size_converted = manifest_diff.total_size; + guint64 n_removed_converted = manifest_diff.n_removed; + guint64 removed_size_converted = manifest_diff.removed_size; + guint64 n_added_converted = manifest_diff.n_added; + guint64 added_size_converted = manifest_diff.added_size; + diff->total = g_variant_new ("t", total_converted); + diff->total_size = g_variant_new ("t", total_size_converted); + diff->total_removed = g_variant_new ("t", n_removed_converted); + diff->removed_size = g_variant_new ("t", removed_size_converted); + diff->total_added = g_variant_new ("t", n_added_converted); + diff->added_size = g_variant_new ("t", added_size_converted); + } + if (diff->total == NULL || diff->total_size == NULL || diff->total_removed == NULL + || diff->removed_size == NULL || diff->total_added == NULL || diff->added_size == NULL) + return FALSE; + + return TRUE; +} + static void rpm_diff_add_layered_diff (RpmDiff *diff, RpmOstreePackage *old_pkg, DnfPackage *new_pkg) { @@ -519,6 +585,24 @@ rpm_diff_is_empty (RpmDiff *diff) return !diff->upgraded->len && !diff->downgraded->len && !diff->removed->len && !diff->added->len; } +static gboolean +manifest_diff_is_empty (ManifestDiff *diff) +{ + g_assert (diff->initialized); + + int removed = 0; + int added = 0; + g_variant_get (diff->total_removed, "t", &removed); + g_variant_get (diff->total_added, "t", &added); + if (!removed && !added) + { + return TRUE; + } + + return !diff->total && !diff->total_size && !diff->total_removed && !diff->removed_size + && !diff->total_added && !diff->added_size; +} + static GVariant * rpm_diff_variant_new (RpmDiff *diff) { @@ -539,6 +623,35 @@ rpm_diff_variant_new (RpmDiff *diff) return g_variant_dict_end (&dict); } +static GVariant * +manifest_diff_variant_new (ManifestDiff *diff) +{ + guint64 total_converted = 0; + guint64 total_size_converted = 0; + guint64 total_removed_converted = 0; + guint64 removed_size_converted = 0; + guint64 total_added_converted = 0; + guint64 added_size_converted = 0; + + g_variant_get (diff->total, "t", &total_converted); + g_variant_get (diff->total_size, "t", &total_size_converted); + g_variant_get (diff->total_removed, "t", &total_removed_converted); + g_variant_get (diff->removed_size, "t", &removed_size_converted); + g_variant_get (diff->total_added, "t", &total_added_converted); + g_variant_get (diff->added_size, "t", &added_size_converted); + + g_auto (GVariantDict) manifest_dict; + g_variant_dict_init (&manifest_dict, NULL); + g_variant_dict_insert (&manifest_dict, "total", "t", total_converted); + g_variant_dict_insert (&manifest_dict, "total_size", "t", total_size_converted); + g_variant_dict_insert (&manifest_dict, "total_removed", "t", total_removed_converted); + g_variant_dict_insert (&manifest_dict, "removed_size", "t", removed_size_converted); + g_variant_dict_insert (&manifest_dict, "total_added", "t", total_added_converted); + g_variant_dict_insert (&manifest_dict, "added_size", "t", added_size_converted); + + return g_variant_dict_end (&manifest_dict); +} + static DnfPackage * find_package (DnfSack *sack, gboolean newer, RpmOstreePackage *pkg) { @@ -687,13 +800,19 @@ rpmostreed_update_generate_variant (OstreeDeployment *booted_deployment, } else { - if (!ostree_repo_resolve_rev_ext (repo, r.refspec.c_str (), TRUE, - static_cast (0), - &new_base_checksum_owned, error)) - return FALSE; - new_base_checksum = new_base_checksum_owned; - /* just assume that the hypothetical new deployment would also be layered if we are */ - is_new_layered = (current_base_checksum_owned != NULL); + auto refspectype = rpmostreecxx::refspec_classify (r.refspec); + if (refspectype != rpmostreecxx::RefspecType::Container) + { + if (!ostree_repo_resolve_rev_ext (repo, r.refspec.c_str (), TRUE, + static_cast (0), + &new_base_checksum_owned, error)) + { + return FALSE; + } + new_base_checksum = new_base_checksum_owned; + /* just assume that the hypothetical new deployment would also be layered if we are */ + is_new_layered = (current_base_checksum_owned != NULL); + } } /* Graciously handle rev no longer in repo; e.g. mucking around with rebase/rollback; we @@ -725,6 +844,10 @@ rpmostreed_update_generate_variant (OstreeDeployment *booted_deployment, }; rpm_diff_init (&rpm_diff); + g_auto (ManifestDiff) manifest_diff = { + 0, + }; + manifest_diff_init (&manifest_diff); /* we'll need these later for advisories, so just keep them around */ g_autoptr (GPtrArray) ostree_modified_new = NULL; g_autoptr (GPtrArray) rpmmd_modified_new = NULL; @@ -744,15 +867,53 @@ rpmostreed_update_generate_variant (OstreeDeployment *booted_deployment, * - if a new base checksum was pulled, do a db diff of the old and new bases * - if there are currently any layered pkgs, lookup in sack for newer versions */ + gboolean rpm_diff_fail = FALSE; if (is_new_checksum) { if (!rpm_diff_add_db_diff (&rpm_diff, repo, RPM_OSTREE_PKG_TYPE_BASE, current_base_checksum, new_base_checksum, &ostree_modified_new, cancellable, error)) - return FALSE; + { + rpm_diff_fail = TRUE; + } + } + else + { + rpm_diff_fail = TRUE; } /* now we look at the rpm-md/layering side */ + const OstreeRepo &tmp_repo = *repo; + const GCancellable &tmp_cancellable = *cancellable; + g_autofree char *origin_remote = NULL; + g_autofree char *origin_ref = NULL; + auto refspectype = rpmostreecxx::refspec_classify (r.refspec); + if (refspectype != rpmostreecxx::RefspecType::Container) + { + if (!ostree_parse_refspec (r.refspec.c_str (), &origin_remote, &origin_ref, error)) + return FALSE; + } + + if (refspectype == rpmostreecxx::RefspecType::Container) + { + CXX_TRY_VAR (res, + rpmostreecxx::compare_local_to_remote_container (tmp_repo, tmp_cancellable, + r.refspec.c_str ()), + error); + + gboolean manifest_diff_fail = FALSE; + + if (!manifest_diff_add_db_diff (&manifest_diff, *res, cancellable, error)) + { + manifest_diff_fail = TRUE; + } + + if (rpm_diff_fail && manifest_diff_fail) + { + *out_update = NULL; + return TRUE; + } + } /* check that it's actually layered (i.e. the requests are not all just dormant) */ if (sack && is_new_layered && rpmostree_origin_has_packages (origin)) @@ -767,8 +928,15 @@ rpmostreed_update_generate_variant (OstreeDeployment *booted_deployment, if (!rpm_diff_is_empty (&rpm_diff)) g_variant_dict_insert (dict, "rpm-diff", "@a{sv}", rpm_diff_variant_new (&rpm_diff)); - /* now we look for advisories */ + gboolean check_container_manifest_diff = FALSE; + if (!manifest_diff_is_empty (&manifest_diff)) + { + g_variant_dict_insert (dict, "manifest-diff", "@a{sv}", + manifest_diff_variant_new (&manifest_diff)); + check_container_manifest_diff = TRUE; + } + /* now we look for advisories */ if (sack && (ostree_modified_new || rpmmd_modified_new)) { /* let's just merge the two now for convenience */ @@ -802,7 +970,7 @@ rpmostreed_update_generate_variant (OstreeDeployment *booted_deployment, } /* but if there are no updates, then just ditch the whole thing and return NULL */ - if (is_new_checksum || rpmmd_modified_new) + if (is_new_checksum || rpmmd_modified_new || check_container_manifest_diff) { /* include a "state" checksum for cache invalidation; for now this is just the * checksum of the deployment against which we ran, though we could base it off more diff --git a/src/daemon/rpmostreed-os.cxx b/src/daemon/rpmostreed-os.cxx index 090c2dfd13..52185c663b 100644 --- a/src/daemon/rpmostreed-os.cxx +++ b/src/daemon/rpmostreed-os.cxx @@ -36,6 +36,11 @@ #include "rpmostreed-transaction.h" #include "rpmostreed-utils.h" +#include + +#include +#include + typedef struct _RpmostreedOSClass RpmostreedOSClass; struct _RpmostreedOS @@ -141,7 +146,7 @@ os_authorize_method (GDBusInterfaceSkeleton *interface, GDBusMethodInvocation *i else if (g_strcmp0 (method_name, "GetDeploymentBootConfig") == 0 || g_strcmp0 (method_name, "ListRepos") == 0 || g_strcmp0 (method_name, "WhatProvides") == 0 - || g_strcmp0 (method_name, "GetPackages") == 0) + || g_strcmp0 (method_name, "GetPackages") == 0 || g_strcmp0 (method_name, "Search") == 0) { /* Note: early return here because no need authentication * for these methods @@ -1138,6 +1143,189 @@ os_handle_get_packages (RPMOSTreeOS *interface, GDBusMethodInvocation *invocatio return TRUE; } +/* helper function to sort and search within a set of (const gchar *) */ +struct cstrless +{ + bool + operator() (const gchar *a, const gchar *b) const + { + return strcmp (a, b) < 0; + } +}; + +/* wrapper function to both query for packages and add them to the builder */ +static void +query_results_to_builder (HyQuery query, GVariantBuilder *builder, const gchar *id, + std::set *result_set) +{ + g_autoptr (GPtrArray) pkglist = hy_query_run (query); + for (guint i = 0; i < pkglist->len && (*result_set).size () < 50; i++) + { + auto pkg = static_cast (g_ptr_array_index (pkglist, i)); + if (!(*result_set).count (dnf_package_get_name (pkg))) + { + os_add_package_info_to_builder (pkg, builder, id); + (*result_set).insert (dnf_package_get_name (pkg)); + } + } +} + +/* helper function to apply Name/Summary or HY_EQ/HY_SUBSTR filters on search term */ +static void +apply_search_filter (HyQuery *query, int keyname, const gchar *const name, int cmp_type) +{ + if (!hy_is_glob_pattern (name)) + { + hy_query_filter (*query, keyname, cmp_type | HY_ICASE, name); + } + else + { + hy_query_filter (*query, keyname, HY_GLOB | HY_ICASE, name); + } +} + +/* helper function to filter package query results */ +static void +search_packages_by_filter (HyQuery query, GVariantBuilder *builder, const gchar *const *names, + std::vector keynames, const gchar *id) +{ + std::set result_set; + HyQuery intermediate_query = hy_query_clone (query); + HyQuery final_query = hy_query_clone (query); + + int names_count = 0; + for (guint i = 0; names[i] != NULL; i++) + { + names_count++; + } + + /* Name/Summary matches */ + if (keynames.size () < 2) + { + hy_query_clear (query); + for (guint i = 0; names[i] != NULL; i++) + { + apply_search_filter (&query, keynames[0], names[i], HY_EQ); + } + query_results_to_builder (query, builder, id, &result_set); + + hy_query_clear (query); + for (guint i = 0; names[i] != NULL; i++) + { + apply_search_filter (&query, keynames[0], names[i], HY_SUBSTR); + } + query_results_to_builder (query, builder, id, &result_set); + } + + /* Name AND Summary matches for more than one search term */ + /* ========================================================================================= + For each search term, apply a query with the keyname filter (Name or Summary) and unions the + results. This allows multi-term searches to return matches when search terms are found in + either the Name or Summary of a package. After this, return the intersection of the results + for each search term to filter out results that do not contain all matching terms. + ========================================================================================= */ + else if (keynames.size () >= 2 && names_count >= 2) + { + + for (guint i = 0; names[i] != NULL; i++) + { + hy_query_clear (intermediate_query); + for (guint j = 0; j < keynames.size (); j++) + { + hy_query_clear (query); + apply_search_filter (&query, keynames[j], names[i], HY_EQ); + + if (j != 0) + { + hy_query_union (intermediate_query, query); + } + else + { + intermediate_query = hy_query_clone (query); + } + + hy_query_clear (query); + apply_search_filter (&query, keynames[j], names[i], HY_SUBSTR); + hy_query_union (intermediate_query, query); + } + + if (i != 0) + { + hy_query_intersection (final_query, intermediate_query); + } + else + { + final_query = hy_query_clone (intermediate_query); + } + } + query_results_to_builder (final_query, builder, id, &result_set); + } + + /* Name AND Summary matches for only one search term */ + /* ========================================================================================= + For the case of a single search term, return the intersection of both Name and Summary matches + of the search term (instead of the union for multi-term searches). + ========================================================================================= */ + else if (keynames.size () >= 2 && names_count < 2) + { + for (guint i = 0; i < keynames.size (); i++) + { + hy_query_clear (query); + apply_search_filter (&query, keynames[i], names[0], HY_EQ); + intermediate_query = hy_query_clone (query); + + hy_query_clear (query); + apply_search_filter (&query, keynames[i], names[0], HY_SUBSTR); + hy_query_union (intermediate_query, query); + + if (i != 0) + { + hy_query_intersection (final_query, intermediate_query); + } + else + { + final_query = hy_query_clone (intermediate_query); + } + } + query_results_to_builder (final_query, builder, id, &result_set); + } +} + +static gboolean +os_handle_search (RPMOSTreeOS *interface, GDBusMethodInvocation *invocation, + const gchar *const *names) +{ + GError *local_error = NULL; + g_autoptr (GCancellable) cancellable = NULL; + + sd_journal_print (LOG_INFO, "Handling Search for caller %s", + g_dbus_method_invocation_get_sender (invocation)); + + g_autoptr (DnfContext) dnfctx + = os_create_dnf_context_simple (interface, TRUE, cancellable, &local_error); + if (dnfctx == NULL) + return os_throw_dbus_invocation_error (invocation, &local_error); + + hy_autoquery HyQuery query = hy_query_create (dnf_context_get_sack (dnfctx)); + + GVariantBuilder builder; + g_variant_builder_init (&builder, (const GVariantType *)"aa{sv}"); + + std::vector keynames_a = { HY_PKG_NAME, HY_PKG_SUMMARY }; + search_packages_by_filter (query, &builder, names, keynames_a, "match_group_a"); + + std::vector keynames_b = { HY_PKG_NAME }; + search_packages_by_filter (query, &builder, names, keynames_b, "match_group_b"); + + std::vector keynames_c = { HY_PKG_SUMMARY }; + search_packages_by_filter (query, &builder, names, keynames_c, "match_group_c"); + + GVariant *pkgs_result = g_variant_builder_end (&builder); + g_dbus_method_invocation_return_value (invocation, g_variant_new ("(@aa{sv})", pkgs_result)); + + return TRUE; +} + /* This is an older variant of Cleanup, kept for backcompat */ static gboolean os_handle_clear_rollback_target (RPMOSTreeOS *interface, GDBusMethodInvocation *invocation, @@ -1813,6 +2001,7 @@ rpmostreed_os_iface_init (RPMOSTreeOSIface *iface) iface->handle_finalize_deployment = os_handle_finalize_deployment; iface->handle_what_provides = os_handle_what_provides; iface->handle_get_packages = os_handle_get_packages; + iface->handle_search = os_handle_search; /* legacy cleanup API; superseded by Cleanup() */ iface->handle_clear_rollback_target = os_handle_clear_rollback_target; /* legacy deployment change API; superseded by UpdateDeployment() */ diff --git a/src/libpriv/rpmostree-core.cxx b/src/libpriv/rpmostree-core.cxx index 9ac15b3154..5c3b0144b0 100644 --- a/src/libpriv/rpmostree-core.cxx +++ b/src/libpriv/rpmostree-core.cxx @@ -1466,7 +1466,18 @@ check_goal_solution (RpmOstreeContext *self, GPtrArray *removed_pkgnames, * for it anyway so that we get a bug report in case it somehow happens. */ { g_autoptr (GPtrArray) packages = dnf_goal_get_packages (goal, DNF_PACKAGE_INFO_REINSTALL, -1); - g_assert_cmpint (packages->len, ==, 0); + if (packages->len > 0) + { + g_autoptr (GString) buf = g_string_new (""); + for (guint i = 0; i < packages->len; i++) + { + if (i > 0) + g_string_append_c (buf, ' '); + auto pkg = static_cast (packages->pdata[i]); + g_string_append (buf, dnf_package_get_name (pkg)); + } + return glnx_throw (error, "Request to reinstall exact base package versions: %s", buf->str); + } } /* Look at UPDATE and DOWNGRADE, and see whether they're doing what we expect */ diff --git a/src/libpriv/rpmostree-kernel.cxx b/src/libpriv/rpmostree-kernel.cxx index 2cf6d00fa8..e5dcb8f1f3 100644 --- a/src/libpriv/rpmostree-kernel.cxx +++ b/src/libpriv/rpmostree-kernel.cxx @@ -89,7 +89,8 @@ find_kernel_and_initramfs_in_bootdir (int rootfs_dfd, const char *bootdir, char if (out_ksuffix ? g_str_has_prefix (name, "vmlinuz-") : g_str_equal (name, "vmlinuz")) { if (ret_kernel) - return glnx_throw (error, "Multiple vmlinuz%s in %s", out_ksuffix ? "-" : "", bootdir); + return glnx_throw (error, "Multiple vmlinuz%s in %s, occurrences '%s' and '%s/%s'", + out_ksuffix ? "-" : "", bootdir, ret_kernel, bootdir, name); if (out_ksuffix) ret_ksuffix = g_strdup (name + strlen ("vmlinuz-")); ret_kernel = g_strconcat (bootdir, "/", name, NULL); @@ -97,7 +98,8 @@ find_kernel_and_initramfs_in_bootdir (int rootfs_dfd, const char *bootdir, char else if (g_str_equal (name, "initramfs.img") || g_str_has_prefix (name, "initramfs-")) { if (ret_initramfs) - return glnx_throw (error, "Multiple initramfs- in %s", bootdir); + return glnx_throw (error, "Multiple initramfs- in %s, occurrences '%s' and '%s/%s'", + bootdir, ret_initramfs, bootdir, name); ret_initramfs = g_strconcat (bootdir, "/", name, NULL); } } diff --git a/src/libpriv/rpmostree-postprocess.cxx b/src/libpriv/rpmostree-postprocess.cxx index bfadaa73dd..9b38da931a 100644 --- a/src/libpriv/rpmostree-postprocess.cxx +++ b/src/libpriv/rpmostree-postprocess.cxx @@ -397,8 +397,8 @@ postprocess_final (int rootfs_dfd, rpmostreecxx::Treefile &treefile, gboolean un /* Temporary workaround for https://github.com/openshift/os/issues/1036. */ { - rust::Vec child_argv = { rust::String ("semodule"), rust::String ("-n"), - rust::String ("--rebuild-if-modules-changed") }; + rust::Vec child_argv + = { rust::String ("semodule"), rust::String ("-n"), rust::String ("--refresh") }; ROSCXX_TRY (bubblewrap_run_sync (rootfs_dfd, child_argv, false, (bool)unified_core_mode), error); } diff --git a/tests/common/libvm.sh b/tests/common/libvm.sh index 25f349e8bf..c5bf52008e 100644 --- a/tests/common/libvm.sh +++ b/tests/common/libvm.sh @@ -66,7 +66,7 @@ vm_kola_spawn() { exit 1 fi setpriv --pdeathsig SIGKILL -- \ - env MANTLE_SSH_DIR="$PWD/kola-ssh" kola spawn -p qemu-unpriv \ + env MANTLE_SSH_DIR="$PWD/kola-ssh" kola spawn -p qemu \ --qemu-image "$test_image" -v --idle \ --json-info-fd 4 --output-dir "$outputdir" & # hack; need cleaner API for async kola spawn diff --git a/tests/kolainst/destructive/container-image b/tests/kolainst/destructive/container-image index 4cb34d5f8a..fc812d975f 100755 --- a/tests/kolainst/destructive/container-image +++ b/tests/kolainst/destructive/container-image @@ -162,9 +162,7 @@ EOF if test "${touched_resolv_conf}" -eq 1; then rm -vf /etc/resolv.conf fi - derived=oci:$image_dir:derived - skopeo copy containers-storage:localhost/fcos-derived $derived - rpm-ostree rebase ostree-unverified-image:$derived + rpm-ostree rebase ostree-unverified-image:containers-storage:localhost/fcos-derived ostree container image list --repo=/ostree/repo | tee imglist.txt assert_streq "$(wc -l < imglist.txt)" 1 rm $image_dir -rf @@ -181,7 +179,7 @@ EOF assert_streq $(rpm -q baz) baz-2.0-1.${arch} test -f /usr/bin/baz ! rpm -q nano - rpmostree_assert_status ".deployments[0][\"container-image-reference\"] == \"ostree-unverified-image:oci:$image_dir:derived\"" + rpmostree_assert_status ".deployments[0][\"container-image-reference\"] == \"ostree-unverified-image:containers-storage:localhost/fcos-derived\"" # We'll test the "apply" automatic updates policy here systemctl stop rpm-ostreed @@ -190,9 +188,7 @@ EOF rpm-ostree reload # Now revert back to the base image, but keep our layered package foo - rm "${image_dir}" -rf - skopeo copy containers-storage:localhost/fcos ${image}:latest - rpm-ostree rebase ostree-unverified-image:${image}:latest + rpm-ostree rebase ostree-unverified-image:containers-storage:localhost/fcos /tmp/autopkgtest-reboot 4 ;; 4) @@ -204,7 +200,7 @@ EOF fatal "found $p" fi done - rpmostree_assert_status ".deployments[0][\"container-image-reference\"] == \"ostree-unverified-image:oci:$image_dir:latest\"" + rpmostree_assert_status ".deployments[0][\"container-image-reference\"] == \"ostree-unverified-image:containers-storage:localhost/fcos\"" ;; *) echo "unexpected mark: ${AUTOPKGTEST_REBOOT_MARK}"; exit 1;; esac diff --git a/tests/kolainst/destructive/container-update-check b/tests/kolainst/destructive/container-update-check new file mode 100755 index 0000000000..d1124c47ad --- /dev/null +++ b/tests/kolainst/destructive/container-update-check @@ -0,0 +1,117 @@ +#!/bin/bash +## kola: +## # Increase timeout since this test has a lot of I/O and involves rebasing +## timeoutMin: 15 +## # This test only runs on FCOS due to a problem with skopeo copy on +## # RHCOS. See: https://github.com/containers/skopeo/issues/1846 +## distros: fcos +## # Needs internet access as we fetch files from koji +## tags: "needs-internet platform-independent" +## minMemory: 2048 +# +# Copyright (C) 2023 Red Hat, Inc. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. ${KOLA_EXT_DATA}/libtest.sh + +set -x + +libtest_prepare_offline +cd "$(mktemp -d)" + +# TODO: It'd be much better to test this via a registry +image_dir=/var/tmp/fcos +image=oci:$image_dir + +case "${AUTOPKGTEST_REBOOT_MARK:-}" in + "") + rpm-ostree upgrade --check > out.txt || true + assert_file_has_content_literal out.txt 'No updates available.' + + checksum=$(rpm-ostree status --json | jq -r '.deployments[0].checksum') + rm ${image_dir} -rf + # Since we're switching OS update stream, turn off zincati + systemctl mask --now zincati + ostree container encapsulate --repo=/ostree/repo ${checksum} "${image}" --label ostree.bootable=TRUE + + skopeo copy $image containers-storage:localhost/fcos + rm "${image_dir}" -rf + td=$(mktemp -d) + cd ${td} +cat > Containerfile << EOF +FROM localhost/fcos +# RUN rpm-ostree install man +EOF + + touched_resolv_conf=0 + if test '!' -f /etc/resolv.conf; then + podmanv=$(podman --version) + case "${podmanv#podman version }" in + 3.*) touched_resolv_conf=1; touch /etc/resolv.conf;; + esac + fi + podman build --net=host -t localhost/fcos-derived --squash . + if test "${touched_resolv_conf}" -eq 1; then + rm -vf /etc/resolv.conf + fi + + rpm-ostree rebase ostree-unverified-image:containers-storage:localhost/fcos-derived + rm $image_dir -rf + + /tmp/autopkgtest-reboot 1 + ;; + 1) + rpm-ostree status + rpm-ostree upgrade --check > out.txt || true + assert_file_has_content_literal out.txt 'No updates available.' + + checksum=$(rpm-ostree status --json | jq -r '.deployments[0].checksum') + rm ${image_dir} -rf + systemctl mask --now zincati + ostree container encapsulate --repo=/ostree/repo ${checksum} "${image}" --label ostree.bootable=TRUE + + skopeo copy $image containers-storage:localhost/fcos + rm "${image_dir}" -rf + td=$(mktemp -d) + cd ${td} +cat > Containerfile << EOF +FROM localhost/fcos +RUN rpm-ostree install man +EOF + + touched_resolv_conf=0 + if test '!' -f /etc/resolv.conf; then + podmanv=$(podman --version) + case "${podmanv#podman version }" in + 3.*) touched_resolv_conf=1; touch /etc/resolv.conf;; + esac + fi + podman build --net=host -t localhost/fcos-derived --squash . + if test "${touched_resolv_conf}" -eq 1; then + rm -vf /etc/resolv.conf + fi + + rpm-ostree upgrade --check > out.txt || true + assert_file_has_content_literal out.txt 'AvailableUpdate:' + assert_file_has_content_literal out.txt 'Total layers:' + assert_file_has_content_literal out.txt 'Size:' + assert_file_has_content_literal out.txt 'Removed layers:' + assert_file_has_content_literal out.txt 'Added layers:' + +esac diff --git a/tests/kolainst/nondestructive/misc.sh b/tests/kolainst/nondestructive/misc.sh index 6965b2f280..223bd45d61 100755 --- a/tests/kolainst/nondestructive/misc.sh +++ b/tests/kolainst/nondestructive/misc.sh @@ -101,6 +101,39 @@ rpmostree_busctl_call_os GetPackages as 1 should-not-exist-p-equals-np > out.txt assert_file_has_content_literal out.txt 'aa{sv} 0' echo "ok dbus GetPackages" +rpmostree_busctl_call_os Search as 1 testdaemon > out.txt +assert_file_has_content_literal out.txt '"epoch" t 0' +assert_file_has_content_literal out.txt '"reponame" s "libtest"' +assert_file_has_content_literal out.txt '"nevra" s "testdaemon' +rpmostree_busctl_call_os Search as 1 should-not-exist-p-equals-np > out.txt +assert_file_has_content_literal out.txt 'aa{sv} 0' +echo "ok dbus Search" + +rpm-ostree search testdaemon > out.txt +assert_file_has_content_literal out.txt '===== Name Matched =====' +assert_file_has_content_literal out.txt 'testdaemon : awesome-daemon-for-testing' +echo "ok Search name match" + +rpm-ostree search awesome-daemon > out.txt +assert_file_has_content_literal out.txt '===== Summary Matched =====' +assert_file_has_content_literal out.txt 'testdaemon : awesome-daemon-for-testing' +echo "ok Search summary match" + +rpm-ostree search testdaemon awesome-daemon > out.txt +assert_file_has_content_literal out.txt '===== Summary & Name Matched =====' +assert_file_has_content_literal out.txt 'testdaemon : awesome-daemon-for-testing' +echo "ok Search name and summary match" + +rpm-ostree search "test*" > out.txt +assert_file_has_content_literal out.txt '===== Summary & Name Matched =====' +assert_file_has_content_literal out.txt '===== Name Matched =====' +assert_file_has_content_literal out.txt '===== Summary Matched =====' +assert_file_has_content_literal out.txt 'testdaemon : awesome-daemon-for-testing' +assert_file_has_content_literal out.txt 'testpkg-etc : testpkg-etc' +assert_file_has_content_literal out.txt 'testpkg-post-infinite-loop : testpkg-post-infinite-loop' +assert_file_has_content_literal out.txt 'testpkg-touch-run : testpkg-touch-run' +echo "ok Search glob pattern match" + # Verify operations as non-root runuser -u core rpm-ostree status echo "ok status doesn't require root" diff --git a/tests/vm.sh b/tests/vm.sh index a54f85d8a4..996f67304f 100755 --- a/tests/vm.sh +++ b/tests/vm.sh @@ -39,7 +39,7 @@ spawn_vm() { exec 4> .kolavm/info.json env MANTLE_SSH_DIR="$PWD/.kolavm/ssh" \ - kola spawn -k -p qemu-unpriv \ + kola spawn -k -p qemu \ --qemu-image "$image" -v --idle \ --json-info-fd 4 --output-dir "$PWD/.kolavm/output" &