1 // Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved.
2 //
3 // StratoVirt is licensed under Mulan PSL v2.
4 // You can use this software according to the terms and conditions of the Mulan
5 // PSL v2.
6 // You may obtain a copy of Mulan PSL v2 at:
7 //         http://license.coscl.org.cn/MulanPSL2
8 // THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
9 // KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
10 // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
11 // See the Mulan PSL v2 for more details.
12 
13 use std::path::{Path, PathBuf};
14 
15 use anyhow::{Context, Ok, Result};
16 use clap::{builder::NonEmptyStringValueParser, Parser};
17 
18 use crate::container::{Action, Container, Launcher};
19 use crate::linux::LinuxContainer;
20 use oci_spec::runtime::RuntimeConfig;
21 
22 /// Create a container from a bundle directory
23 #[derive(Parser, Debug)]
24 pub struct Create {
25     /// File to write the container PID to
26     #[arg(short, long)]
27     pub pid_file: Option<PathBuf>,
28     /// Path to the bundle directory, defaults to the current working directory.
29     #[arg(short, long, default_value = ".")]
30     pub bundle: PathBuf,
31     /// Path to an AF_UNIX socket which will receive the pseudoterminal master
32     /// at a file descriptor.
33     #[arg(short, long)]
34     pub console_socket: Option<PathBuf>,
35     /// Container ID to create.
36     #[arg(value_parser = NonEmptyStringValueParser::new(), required = true)]
37     pub container_id: String,
38 }
39 
40 impl Create {
launcher(&self, root: &Path, exist: &mut bool) -> Result<Launcher>41     fn launcher(&self, root: &Path, exist: &mut bool) -> Result<Launcher> {
42         let bundle_path = self
43             .bundle
44             .canonicalize()
45             .with_context(|| "Failed to canonicalize bundle path")?;
46         let config_path = bundle_path
47             .join("config.json")
48             .to_string_lossy()
49             .to_string();
50         let mut config = RuntimeConfig::from_file(&config_path)?;
51         let mut rootfs_path = PathBuf::from(config.root.path);
52 
53         if !rootfs_path.is_absolute() {
54             rootfs_path = bundle_path.join(rootfs_path);
55         }
56         config.root.path = rootfs_path.to_string_lossy().to_string();
57 
58         let container: Box<dyn Container> = Box::new(LinuxContainer::new(
59             &self.container_id,
60             &root.to_string_lossy().to_string(),
61             &config,
62             &self.console_socket,
63             exist,
64         )?);
65         Ok(Launcher::new(
66             &bundle_path,
67             root,
68             true,
69             container,
70             self.pid_file.clone(),
71         ))
72     }
73 
run(&self, root: &Path, exist: &mut bool) -> Result<()>74     pub fn run(&self, root: &Path, exist: &mut bool) -> Result<()> {
75         let mut launcher = self.launcher(root, exist)?;
76         launcher.launch(Action::Create)?;
77         Ok(())
78     }
79 }
80