Skip to content

Commit 12dac81

Browse files
authored
Merge pull request #36 from slp/macos-rosetta
macos: add support for running x86 microVMs on ARM64
2 parents e67d0ea + 242a740 commit 12dac81

File tree

4 files changed

+122
-62
lines changed

4 files changed

+122
-62
lines changed

Cargo.lock

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

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "krunvm"
3-
version = "0.2.2"
3+
version = "0.2.3"
44
authors = ["Sergio Lopez <[email protected]>"]
55
description = "Create microVMs from OCI images"
66
repository = "https://github.com/containers/krunvm"

src/create.rs

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
use std::fs;
55
use std::io::Write;
6+
#[cfg(target_os = "macos")]
7+
use std::path::Path;
68
use std::process::Command;
79

810
use super::utils::{
@@ -11,6 +13,9 @@ use super::utils::{
1113
};
1214
use crate::{ArgMatches, KrunvmConfig, VmConfig, APP_NAME};
1315

16+
#[cfg(target_os = "macos")]
17+
const KRUNVM_ROSETTA_FILE: &str = ".krunvm-rosetta";
18+
1419
fn fix_resolv_conf(rootfs: &str, dns: &str) -> Result<(), std::io::Error> {
1520
let resolvconf_dir = format!("{}/etc/", rootfs);
1621
fs::create_dir_all(resolvconf_dir)?;
@@ -62,7 +67,7 @@ fn export_container_config(
6267
}
6368

6469
pub fn create(cfg: &mut KrunvmConfig, matches: &ArgMatches) {
65-
let cpus = match matches.value_of("cpus") {
70+
let mut cpus = match matches.value_of("cpus") {
6671
Some(c) => match c.parse::<u32>() {
6772
Err(_) => {
6873
println!("Invalid value for \"cpus\"");
@@ -114,6 +119,47 @@ pub fn create(cfg: &mut KrunvmConfig, matches: &ArgMatches) {
114119
}
115120

116121
let mut args = get_buildah_args(cfg, BuildahCommand::From);
122+
123+
#[cfg(target_os = "macos")]
124+
let force_x86 = matches.is_present("x86");
125+
126+
#[cfg(target_os = "macos")]
127+
if force_x86 {
128+
let home = match std::env::var("HOME") {
129+
Err(e) => {
130+
println!("Error reading \"HOME\" enviroment variable: {}", e);
131+
std::process::exit(-1);
132+
}
133+
Ok(home) => home,
134+
};
135+
136+
let path = format!("{}/{}", home, KRUNVM_ROSETTA_FILE);
137+
if !Path::new(&path).is_file() {
138+
println!(
139+
"
140+
To use Rosetta for Linux you need to create the file...
141+
142+
{}
143+
144+
...with the contents that the \"rosetta\" binary expects to be served from
145+
its specific ioctl.
146+
147+
For more information, please refer to this post:
148+
https://threedots.ovh/blog/2022/06/quick-look-at-rosetta-on-linux/
149+
",
150+
path
151+
);
152+
std::process::exit(-1);
153+
}
154+
155+
if cpus != 1 {
156+
println!("x86 microVMs on Aarch64 are restricted to 1 CPU");
157+
cpus = 1;
158+
}
159+
args.push("--arch".to_string());
160+
args.push("x86_64".to_string());
161+
}
162+
117163
args.push(image.to_string());
118164

119165
let output = match Command::new("buildah")
@@ -161,6 +207,10 @@ pub fn create(cfg: &mut KrunvmConfig, matches: &ArgMatches) {
161207
let rootfs = mount_container(cfg, &vmcfg).unwrap();
162208
export_container_config(cfg, &rootfs, image).unwrap();
163209
fix_resolv_conf(&rootfs, dns).unwrap();
210+
#[cfg(target_os = "macos")]
211+
if force_x86 {
212+
_ = fs::create_dir(format!("{}/.rosetta", rootfs));
213+
}
164214
umount_container(cfg, &vmcfg).unwrap();
165215

166216
cfg.vmconfig_map.insert(name.clone(), vmcfg);

src/main.rs

Lines changed: 69 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -246,65 +246,6 @@ fn main() {
246246
.takes_value(true),
247247
),
248248
)
249-
.subcommand(
250-
App::new("create")
251-
.about("Create a new microVM")
252-
.arg(
253-
Arg::with_name("cpus")
254-
.long("cpus")
255-
.help("Number of vCPUs")
256-
.takes_value(true),
257-
)
258-
.arg(
259-
Arg::with_name("mem")
260-
.long("mem")
261-
.help("Amount of RAM in MiB")
262-
.takes_value(true),
263-
)
264-
.arg(
265-
Arg::with_name("dns")
266-
.long("dns")
267-
.help("DNS server to use in the microVM")
268-
.takes_value(true),
269-
)
270-
.arg(
271-
Arg::with_name("workdir")
272-
.long("workdir")
273-
.short("w")
274-
.help("Working directory inside the microVM")
275-
.takes_value(true)
276-
.default_value(""),
277-
)
278-
.arg(
279-
Arg::with_name("volume")
280-
.long("volume")
281-
.short("v")
282-
.help("Volume in form \"host_path:guest_path\" to be exposed to the guest")
283-
.takes_value(true)
284-
.multiple(true)
285-
.number_of_values(1),
286-
)
287-
.arg(
288-
Arg::with_name("port")
289-
.long("port")
290-
.short("p")
291-
.help("Port in format \"host_port:guest_port\" to be exposed to the host")
292-
.takes_value(true)
293-
.multiple(true)
294-
.number_of_values(1),
295-
)
296-
.arg(
297-
Arg::with_name("name")
298-
.long("name")
299-
.help("Assign a name to the VM")
300-
.takes_value(true),
301-
)
302-
.arg(
303-
Arg::with_name("IMAGE")
304-
.help("OCI image to use as template")
305-
.required(true),
306-
),
307-
)
308249
.subcommand(
309250
App::new("delete").about("Delete an existing microVM").arg(
310251
Arg::with_name("NAME")
@@ -348,6 +289,75 @@ fn main() {
348289
),
349290
);
350291

292+
let mut create = App::new("create")
293+
.about("Create a new microVM")
294+
.arg(
295+
Arg::with_name("cpus")
296+
.long("cpus")
297+
.help("Number of vCPUs")
298+
.takes_value(true),
299+
)
300+
.arg(
301+
Arg::with_name("mem")
302+
.long("mem")
303+
.help("Amount of RAM in MiB")
304+
.takes_value(true),
305+
)
306+
.arg(
307+
Arg::with_name("dns")
308+
.long("dns")
309+
.help("DNS server to use in the microVM")
310+
.takes_value(true),
311+
)
312+
.arg(
313+
Arg::with_name("workdir")
314+
.long("workdir")
315+
.short("w")
316+
.help("Working directory inside the microVM")
317+
.takes_value(true)
318+
.default_value(""),
319+
)
320+
.arg(
321+
Arg::with_name("volume")
322+
.long("volume")
323+
.short("v")
324+
.help("Volume in form \"host_path:guest_path\" to be exposed to the guest")
325+
.takes_value(true)
326+
.multiple(true)
327+
.number_of_values(1),
328+
)
329+
.arg(
330+
Arg::with_name("port")
331+
.long("port")
332+
.short("p")
333+
.help("Port in format \"host_port:guest_port\" to be exposed to the host")
334+
.takes_value(true)
335+
.multiple(true)
336+
.number_of_values(1),
337+
)
338+
.arg(
339+
Arg::with_name("name")
340+
.long("name")
341+
.help("Assign a name to the VM")
342+
.takes_value(true),
343+
)
344+
.arg(
345+
Arg::with_name("IMAGE")
346+
.help("OCI image to use as template")
347+
.required(true),
348+
);
349+
350+
if cfg!(target_os = "macos") {
351+
create = create.arg(
352+
Arg::with_name("x86")
353+
.long("x86")
354+
.short("x")
355+
.help("Create a x86_64 microVM even on an Aarch64 host"),
356+
);
357+
}
358+
359+
app = app.subcommand(create);
360+
351361
let matches = app.clone().get_matches();
352362

353363
#[cfg(target_os = "macos")]

0 commit comments

Comments
 (0)