-
Notifications
You must be signed in to change notification settings - Fork 172
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This is a wrapper around `compose tree` currently.
- Loading branch information
0 parents
commit 35bd3c6
Showing
6 changed files
with
269 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
|
||
/target | ||
**/*.rs.bk |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
[package] | ||
name = "coreos-assembler" | ||
version = "0.1.0" | ||
authors = ["Colin Walters <walters@verbum.org>"] | ||
|
||
[dependencies] | ||
tempfile = "3.0.2" | ||
serde = "1.0" | ||
serde_derive = "1.0" | ||
serde_json = "1.0" | ||
serde_yaml = "0.7" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
FROM registry.fedoraproject.org/fedora:28 | ||
RUN yum -y install rpm-ostree make cargo git && yum clean all | ||
ADD build.sh /root | ||
RUN mkdir /root/src | ||
COPY Cargo.toml /root/src/ | ||
COPY src /root/src/src | ||
RUN ./root/build.sh && rm -f /root/build.sh |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
#!/usr/bin/bash | ||
set -xeuo pipefail | ||
mkdir -p /usr/app/ | ||
cd /usr/app/ | ||
git clone https://github.com/ostreedev/ostree-releng-scripts | ||
cd /root/src | ||
ls -al | ||
cargo build --release | ||
mv target/release/coreos-assembler /usr/bin | ||
rm target -rf |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
#[macro_use] | ||
extern crate serde_derive; | ||
extern crate serde; | ||
extern crate serde_json; | ||
extern crate serde_yaml; | ||
extern crate tempfile; | ||
|
||
use std::{env, fs, io, process, mem}; | ||
use std::ops::Deref; | ||
use std::borrow::Cow; | ||
use std::path::Path; | ||
|
||
mod treefile; | ||
use treefile::TreeComposeConfig; | ||
|
||
// For convenience we allow the list to have multiple packages | ||
// per item (intended for YAML). | ||
fn whitespace_split_packages(pkgs: &Vec<String>) -> Vec<String> { | ||
let mut ret = Vec::with_capacity(pkgs.len()); | ||
for pkg in pkgs { | ||
for pkg_item in pkg.split_whitespace() { | ||
ret.push(pkg_item.into()); | ||
} | ||
} | ||
return ret; | ||
} | ||
|
||
fn manifest_data_to_tmpdir(path: &Path, manifest: &TreeComposeConfig) -> io::Result<tempfile::TempDir> { | ||
let tmpdir = tempfile::tempdir_in("/tmp")?; | ||
let postprocess_script : &str = manifest.postprocess_script.as_ref().map_or("", String::as_str); | ||
for entry in fs::read_dir(path)? { | ||
let entry = entry?; | ||
let path = entry.path(); | ||
if !path.is_file() { | ||
continue; | ||
} | ||
// Hardcoded list of external files | ||
let bn = entry.file_name(); | ||
let bn = bn.to_str().unwrap(); | ||
if bn.ends_with(".repo") || bn.ends_with(".json") | ||
|| bn == "passwd" || bn == "group" || bn == postprocess_script { | ||
fs::copy(path, tmpdir.path().join(bn))?; | ||
} | ||
} | ||
return Ok(tmpdir); | ||
} | ||
|
||
fn is_yaml(name: &str) -> bool { | ||
name.ends_with(".yaml") | ||
} | ||
|
||
fn run() -> Result<(), String> { | ||
let mut manifest_index : Option<usize> = None; | ||
let env_args : Vec<String> = env::args().skip(1).collect(); | ||
// Replace our argv with rpm-ostree compose tree [original argv] | ||
let base_args = &["compose", "tree"]; | ||
let mut args : Vec<Cow<str>> = base_args.iter().map(|v: &&str| *v) | ||
.chain(env_args.iter().map(|v| v.as_str())) | ||
.map(From::from) | ||
.collect(); | ||
for (i,arg) in args.iter().enumerate() { | ||
if is_yaml(&arg) || arg.ends_with(".json") { | ||
manifest_index = Some(i); | ||
} | ||
} | ||
if manifest_index.is_none() { | ||
return Err("no manifest in arguments, expected *.yaml or *.json".into()); | ||
} | ||
let manifest_index = manifest_index.unwrap(); | ||
let manifest_path = (args[manifest_index]).to_string(); | ||
let manifest_path = Path::new(&manifest_path); | ||
let manifest_f = fs::File::open(manifest_path).map_err(|err| err.to_string())?; | ||
|
||
// In the YAML case, we generate JSON from it in a temporary directory, | ||
// copying in the other files that are referenced by the manifest. | ||
let mut tmpd : Option<tempfile::TempDir> = None; | ||
if is_yaml(manifest_path.to_str().unwrap()) { | ||
let mut manifest : TreeComposeConfig = | ||
serde_yaml::from_reader(manifest_f).map_err(|err| err.to_string())?; | ||
if manifest.include.is_some() { | ||
return Err("include: is currently not supported in YAML syntax".into()); | ||
} | ||
let new_pkgs = whitespace_split_packages(&manifest.packages); | ||
manifest.packages = new_pkgs; | ||
println!("Parsed manifest:"); | ||
println!(" {:?}", manifest); | ||
|
||
tmpd = Some(manifest_data_to_tmpdir(manifest_path.parent().unwrap(), &manifest).map_err(|err| err.to_string())?); | ||
let tmpd_v = tmpd.as_ref().unwrap(); | ||
let tmpd_path = tmpd_v.path(); | ||
println!("Converting to JSON, tmpdir={:?}", tmpd_path); | ||
let bfn = manifest_path.file_name().unwrap(); | ||
let bn = bfn.to_str().unwrap().replace(".yaml", ".json"); | ||
let manifest_json_path = tmpd_path.join(bn); | ||
let out_json = fs::File::create(&manifest_json_path).map_err(|err| err.to_string())?; | ||
serde_json::to_writer_pretty(out_json, &manifest).map_err(|err| err.to_string())?; | ||
|
||
// Replace the YAML argument with JSON | ||
let manifest_path_str = manifest_json_path.to_str().unwrap(); | ||
args[manifest_index] = Cow::Owned(manifest_path_str.to_string()); | ||
} | ||
// libc::execve() is unsafe sadly, and also we want to clean up the tmpdir. | ||
// But we basically pass through all arguments other than the manifest | ||
// unchanged. | ||
println!("Executing: rpm-ostree {:?}", args); | ||
let status = process::Command::new("rpm-ostree").args(args.iter().map(|v| v.deref())) | ||
.stdin(process::Stdio::null()).status().map_err(|err| err.to_string())?; | ||
mem::forget(tmpd); | ||
if status.success() { | ||
Ok(()) | ||
} else { | ||
Err(format!("rpm-ostree compose tree failed: {}", status)) | ||
} | ||
} | ||
|
||
fn main() { | ||
::process::exit( | ||
match run() { | ||
Ok(_) => 0, | ||
Err(e) => { println!("{}", e); 1 } | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
#[derive(Serialize, Deserialize, Debug)] | ||
pub enum BootLocation { | ||
#[serde(rename = "both")] | ||
Both, | ||
#[serde(rename = "legacy")] | ||
Legacy, | ||
#[serde(rename = "new")] | ||
New, | ||
} | ||
|
||
impl Default for BootLocation { | ||
fn default() -> Self { | ||
BootLocation::Both | ||
} | ||
} | ||
|
||
#[derive(Serialize, Deserialize, Debug)] | ||
pub enum CheckPasswdType { | ||
#[serde(rename = "none")] | ||
None, | ||
#[serde(rename = "previous")] | ||
Previous, | ||
#[serde(rename = "file")] | ||
File, | ||
#[serde(rename = "data")] | ||
Data, | ||
} | ||
|
||
#[derive(Serialize, Deserialize, Debug)] | ||
pub struct CheckPasswd { | ||
#[serde(rename = "type")] | ||
variant: CheckPasswdType, | ||
filename: Option<String>, | ||
// Skip this for now, a separate file is easier | ||
// and anyways we want to switch to sysusers | ||
// entries: Option<Map<>String>, | ||
} | ||
|
||
#[derive(Serialize, Deserialize, Debug)] | ||
pub struct TreeComposeConfig { | ||
// Compose controls | ||
#[serde(rename = "ref")] | ||
pub treeref: String, | ||
repos: Vec<String>, | ||
#[serde(skip_serializing_if = "Option::is_none")] | ||
pub selinux: Option<bool>, | ||
#[serde(skip_serializing_if = "Option::is_none")] | ||
pub gpg_key: Option<String>, | ||
#[serde(skip_serializing_if = "Option::is_none")] | ||
pub include: Option<String>, | ||
|
||
// Core content | ||
pub packages: Vec<String>, | ||
#[serde(skip_serializing_if = "Option::is_none")] | ||
pub bootstrap_packages: Option<Vec<String>>, | ||
|
||
// Content installation opts | ||
#[serde(skip_serializing_if = "Option::is_none")] | ||
pub documentation: Option<bool>, | ||
#[serde(skip_serializing_if = "Option::is_none")] | ||
pub install_langs: Option<Vec<String>>, | ||
#[serde(skip_serializing_if = "Option::is_none")] | ||
#[serde(rename="initramfs-args")] | ||
pub initramfs_args: Option<Vec<String>>, | ||
|
||
// Tree layout options | ||
#[serde(default)] | ||
pub boot_location: BootLocation, | ||
#[serde(default)] | ||
pub tmp_is_dir: bool, | ||
|
||
// systemd | ||
#[serde(skip_serializing_if = "Option::is_none")] | ||
pub units: Option<Vec<String>>, | ||
#[serde(skip_serializing_if = "Option::is_none")] | ||
pub default_target: Option<String>, | ||
|
||
// versioning | ||
#[serde(skip_serializing_if = "Option::is_none")] | ||
pub releasever: Option<String>, | ||
#[serde(skip_serializing_if = "Option::is_none")] | ||
pub automatic_version_prefix: Option<String>, | ||
#[serde(skip_serializing_if = "Option::is_none")] | ||
#[serde(rename="mutate-os-relase")] | ||
pub mutate_os_release: Option<String>, | ||
|
||
// passwd-related bits | ||
#[serde(skip_serializing_if = "Option::is_none")] | ||
pub etc_group_members: Option<Vec<String>>, | ||
#[serde(skip_serializing_if = "Option::is_none")] | ||
#[serde(rename="preserve-passwd")] | ||
pub preserve_passwd: Option<bool>, | ||
#[serde(skip_serializing_if = "Option::is_none")] | ||
#[serde(rename="check-passwd")] | ||
pub check_passwd: Option<CheckPasswd>, | ||
#[serde(skip_serializing_if = "Option::is_none")] | ||
#[serde(rename="check-groups")] | ||
pub check_groups: Option<CheckPasswd>, | ||
#[serde(skip_serializing_if = "Option::is_none")] | ||
pub ignore_removed_users: Option<Vec<String>>, | ||
#[serde(skip_serializing_if = "Option::is_none")] | ||
pub ignore_removed_groups: Option<Vec<String>>, | ||
|
||
// Content manimulation | ||
#[serde(skip_serializing_if = "Option::is_none")] | ||
#[serde(rename="postprocess-script")] | ||
pub postprocess_script: Option<String>, | ||
#[serde(skip_serializing_if = "Option::is_none")] | ||
#[serde(rename="add-files")] | ||
pub add_files: Option<Vec<String>>, | ||
#[serde(skip_serializing_if = "Option::is_none")] | ||
pub remove_files: Option<Vec<String>>, | ||
#[serde(skip_serializing_if = "Option::is_none")] | ||
#[serde(rename="remove-from-packages")] | ||
pub remove_from_packages: Option<Vec<Vec<String>>>, | ||
} |