Skip to content

Commit c5329d7

Browse files
authored
ci: generate outputs for pinning helios on release branches (#8092)
1 parent 2accbe9 commit c5329d7

File tree

5 files changed

+337
-41
lines changed

5 files changed

+337
-41
lines changed

.github/buildomat/jobs/tuf-repo.sh

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
#: "=/work/manifest.toml",
99
#: "=/work/repo.zip",
1010
#: "=/work/repo.zip.sha256.txt",
11+
#: "=/work/helios.json",
12+
#: "=/work/incorporation.p5m",
13+
#: "=/work/incorporation.p5p",
1114
#: "%/work/*.log",
1215
#: ]
1316
#: access_repos = [
@@ -42,6 +45,21 @@
4245
#: name = "repo.zip.sha256.txt"
4346
#: from_output = "/work/repo.zip.sha256.txt"
4447
#:
48+
#: [[publish]]
49+
#: series = "rot-all"
50+
#: name = "helios.json"
51+
#: from_output = "/work/helios.json"
52+
#:
53+
#: [[publish]]
54+
#: series = "rot-all"
55+
#: name = "incorporation.p5m"
56+
#: from_output = "/work/incorporation.p5m"
57+
#:
58+
#: [[publish]]
59+
#: series = "rot-all"
60+
#: name = "incorporation.p5m"
61+
#: from_output = "/work/incorporation.p5p"
62+
#:
4563

4664
set -o errexit
4765
set -o pipefail
@@ -73,4 +91,4 @@ esac
7391
pfexec zfs create -p "rpool/images/$USER/host"
7492
pfexec zfs create -p "rpool/images/$USER/recovery"
7593

76-
cargo xtask releng --output-dir /work
94+
cargo xtask releng --output-dir /work --mkincorp

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dev-tools/releng/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ omicron-zone-package.workspace = true
2020
reqwest.workspace = true
2121
semver.workspace = true
2222
serde.workspace = true
23+
serde_json.workspace = true
2324
sha2.workspace = true
2425
shell-words.workspace = true
2526
slog.workspace = true

dev-tools/releng/src/helios.rs

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
// This Source Code Form is subject to the terms of the Mozilla Public
2+
// License, v. 2.0. If a copy of the MPL was not distributed with this
3+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4+
5+
use anyhow::Context;
6+
use anyhow::Result;
7+
use camino::Utf8Path;
8+
use camino::Utf8PathBuf;
9+
use fs_err::tokio as fs;
10+
use fs_err::tokio::File;
11+
use serde::Deserialize;
12+
use slog::Logger;
13+
use tokio::io::AsyncWriteExt;
14+
use tokio::io::BufWriter;
15+
16+
use crate::HELIOS_REPO;
17+
use crate::Jobs;
18+
use crate::cmd::Command;
19+
20+
pub const INCORP_NAME: &str =
21+
"consolidation/oxide/omicron-release-incorporation";
22+
const MANIFEST_PATH: &str = "incorporation.p5m";
23+
const REPO_PATH: &str = "incorporation";
24+
pub const ARCHIVE_PATH: &str = "incorporation.p5p";
25+
26+
pub const PUBLISHER: &str = "helios-dev";
27+
28+
pub(crate) enum Action {
29+
Generate { version: String },
30+
Passthru { version: String },
31+
}
32+
33+
pub(crate) async fn push_incorporation_jobs(
34+
jobs: &mut Jobs,
35+
logger: &Logger,
36+
output_dir: &Utf8Path,
37+
action: Action,
38+
) -> Result<()> {
39+
let manifest_path = output_dir.join(MANIFEST_PATH);
40+
let repo_path = output_dir.join(REPO_PATH);
41+
let archive_path = output_dir.join(ARCHIVE_PATH);
42+
43+
fs::remove_dir_all(&repo_path).await.or_else(ignore_not_found)?;
44+
fs::remove_file(&archive_path).await.or_else(ignore_not_found)?;
45+
46+
match action {
47+
Action::Generate { version } => {
48+
jobs.push(
49+
"incorp-manifest",
50+
generate_incorporation_manifest(
51+
logger.clone(),
52+
manifest_path.clone(),
53+
version,
54+
),
55+
);
56+
}
57+
Action::Passthru { version } => {
58+
jobs.push(
59+
"incorp-manifest",
60+
passthru_incorporation_manifest(
61+
logger.clone(),
62+
manifest_path.clone(),
63+
version,
64+
),
65+
);
66+
}
67+
}
68+
69+
jobs.push_command(
70+
"incorp-fmt",
71+
Command::new("pkgfmt").args(["-u", "-f", "v2", manifest_path.as_str()]),
72+
)
73+
.after("incorp-manifest");
74+
75+
jobs.push_command(
76+
"incorp-create",
77+
Command::new("pkgrepo").args(["create", repo_path.as_str()]),
78+
);
79+
80+
let path_args = ["-s", repo_path.as_str()];
81+
jobs.push_command(
82+
"incorp-publisher",
83+
Command::new("pkgrepo")
84+
.arg("add-publisher")
85+
.args(&path_args)
86+
.arg(PUBLISHER),
87+
)
88+
.after("incorp-create");
89+
90+
jobs.push_command(
91+
"incorp-pkgsend",
92+
Command::new("pkgsend")
93+
.arg("publish")
94+
.args(&path_args)
95+
.arg(manifest_path),
96+
)
97+
.after("incorp-fmt")
98+
.after("incorp-publisher");
99+
100+
jobs.push_command(
101+
"helios-incorp",
102+
Command::new("pkgrecv")
103+
.args(path_args)
104+
.args(["-a", "-d", archive_path.as_str()])
105+
.args(["-m", "latest", "-v", "*"]),
106+
)
107+
.after("incorp-pkgsend");
108+
109+
Ok(())
110+
}
111+
112+
async fn generate_incorporation_manifest(
113+
logger: Logger,
114+
path: Utf8PathBuf,
115+
version: String,
116+
) -> Result<()> {
117+
#[derive(Deserialize, PartialEq, Eq, PartialOrd, Ord)]
118+
struct Package {
119+
fmri: String,
120+
}
121+
122+
let mut manifest = BufWriter::new(File::create(path).await?);
123+
let preamble = format!(
124+
r#"set name=pkg.fmri value=pkg://{PUBLISHER}/{INCORP_NAME}@{version},5.11
125+
set name=pkg.summary value="Incorporation to constrain software delivered in Omicron Release V{version} images"
126+
set name=info.classification value="org.opensolaris.category.2008:Meta Packages/Incorporations"
127+
set name=variant.opensolaris.zone value=global value=nonglobal
128+
"#
129+
);
130+
manifest.write_all(preamble.as_bytes()).await?;
131+
132+
let stdout = Command::new("pkg")
133+
.args(["list", "-g", HELIOS_REPO, "-F", "json"])
134+
.args(["-o", "fmri", "*@latest"])
135+
.ensure_stdout(&logger)
136+
.await?;
137+
let packages: Vec<Package> = serde_json::from_str(&stdout)
138+
.context("failed to parse pkgrepo output")?;
139+
let prefix = format!("pkg://{PUBLISHER}/");
140+
for package in packages {
141+
let Some(partial) = package.fmri.strip_prefix(&prefix) else {
142+
continue;
143+
};
144+
let Some((package, _)) = partial.split_once('@') else {
145+
continue;
146+
};
147+
if package == INCORP_NAME || package == "driver/network/opte" {
148+
continue;
149+
}
150+
let line = format!("depend type=incorporate fmri=pkg:/{partial}\n");
151+
manifest.write_all(line.as_bytes()).await?;
152+
}
153+
154+
manifest.shutdown().await?;
155+
Ok(())
156+
}
157+
158+
async fn passthru_incorporation_manifest(
159+
logger: Logger,
160+
path: Utf8PathBuf,
161+
version: String,
162+
) -> Result<()> {
163+
let stdout = Command::new("pkgrepo")
164+
.args(["contents", "-m", "-s", HELIOS_REPO])
165+
.arg(format!("pkg://{PUBLISHER}/{INCORP_NAME}@{version},5.11"))
166+
.ensure_stdout(&logger)
167+
.await?;
168+
fs::write(&path, stdout).await?;
169+
Ok(())
170+
}
171+
172+
fn ignore_not_found(err: std::io::Error) -> Result<(), std::io::Error> {
173+
if err.kind() == std::io::ErrorKind::NotFound { Ok(()) } else { Err(err) }
174+
}

0 commit comments

Comments
 (0)