mirror of
https://github.com/michael-yuji/xc.git
synced 2026-03-18 06:45:39 +01:00
preliminary RUN and FROM directive support, without network
This commit is contained in:
@@ -22,20 +22,25 @@
|
||||
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
// SUCH DAMAGE.
|
||||
|
||||
|
||||
use crate::jailfile::parse::Action;
|
||||
use crate::jailfile::JailContext;
|
||||
use super::Directive;
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use ipc::packet::codec::{List, Maybe};
|
||||
use oci_util::image_reference::ImageReference;
|
||||
use xc::util::gen_id;
|
||||
use std::collections::HashMap;
|
||||
use xc::{util::gen_id, models::network::DnsSetting};
|
||||
use xcd::ipc::*;
|
||||
|
||||
pub(crate) struct FromDirective {
|
||||
image_reference: ImageReference,
|
||||
alias: Option<String>,
|
||||
}
|
||||
|
||||
impl FromDirective {
|
||||
pub(crate) fn from_action(action: &Action) -> Result<FromDirective> {
|
||||
impl Directive for FromDirective {
|
||||
fn from_action(action: &Action) -> Result<FromDirective> {
|
||||
if action.directive_name != "FROM" {
|
||||
bail!("directive_name is not FROM");
|
||||
}
|
||||
@@ -56,7 +61,7 @@ impl FromDirective {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn run_in_context(&self, context: &mut JailContext) -> Result<()> {
|
||||
fn run_in_context(&self, context: &mut JailContext) -> Result<()> {
|
||||
if let Some(container_id) = &context.container_id {
|
||||
let tagged_containers = context.containers.values().collect::<Vec<_>>();
|
||||
if !tagged_containers.contains(&container_id) {
|
||||
@@ -65,12 +70,42 @@ impl FromDirective {
|
||||
}
|
||||
let name = format!("build-{}", gen_id());
|
||||
/* create container */
|
||||
if let Some(alias) = &self.alias {
|
||||
context
|
||||
.containers
|
||||
.insert(alias.to_string(), name.to_string());
|
||||
let req = InstantiateRequest {
|
||||
alt_root: None,
|
||||
name: Some(name.to_string()),
|
||||
hostname: None,
|
||||
copies: List::new(),
|
||||
dns: DnsSetting::Inherit,
|
||||
image_reference: self.image_reference.clone(),
|
||||
no_clean: false,
|
||||
main_norun: true,
|
||||
init_norun: true,
|
||||
deinit_norun: true,
|
||||
persist: true,
|
||||
ips: Vec::new(),
|
||||
main_started_notify: Maybe::None,
|
||||
entry_point: "main".to_string(),
|
||||
entry_point_args: Vec::new(),
|
||||
envs: HashMap::new(),
|
||||
vnet: false,
|
||||
mount_req: Vec::new(),
|
||||
ipreq: Vec::new()
|
||||
};
|
||||
eprintln!("before instantiate");
|
||||
match do_instantiate(&mut context.conn, req)? {
|
||||
Ok(response) => {
|
||||
eprintln!("instantiate resspones: {response:?}");
|
||||
if let Some(alias) = &self.alias {
|
||||
context
|
||||
.containers
|
||||
.insert(alias.to_string(), name.to_string());
|
||||
}
|
||||
context.container_id = Some(name);
|
||||
Ok(())
|
||||
},
|
||||
Err(err) => {
|
||||
bail!("instantiation failure: {err:?}")
|
||||
}
|
||||
}
|
||||
context.container_id = Some(name);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,3 +23,11 @@
|
||||
// SUCH DAMAGE.
|
||||
pub mod from;
|
||||
pub mod run;
|
||||
|
||||
use crate::jailfile::parse::Action;
|
||||
use super::JailContext;
|
||||
|
||||
pub(crate) trait Directive: Sized {
|
||||
fn from_action(action: &Action) -> Result<Self, anyhow::Error>;
|
||||
fn run_in_context(&self, context: &mut JailContext) -> Result<(), anyhow::Error>;
|
||||
}
|
||||
|
||||
@@ -1 +1,116 @@
|
||||
// Copyright (c) 2023 Yan Ka, Chiu.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions, and the following disclaimer,
|
||||
// without modification, immediately at the beginning of the file.
|
||||
// 2. The name of the author may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
// SUCH DAMAGE.
|
||||
//
|
||||
|
||||
use crate::jailfile::JailContext;
|
||||
use crate::jailfile::parse::Action;
|
||||
use super::Directive;
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use freebsd::event::EventFdNotify;
|
||||
use ipc::packet::codec::{Maybe, Fd};
|
||||
use nix::unistd::pipe;
|
||||
use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
use std::os::fd::AsRawFd;
|
||||
use xcd::ipc::*;
|
||||
|
||||
enum Input {
|
||||
File(File),
|
||||
Content(String),
|
||||
None
|
||||
}
|
||||
|
||||
pub(crate) struct RunDirective {
|
||||
arg0: String,
|
||||
args: Vec<String>,
|
||||
envs: HashMap<String, String>,
|
||||
input: Input
|
||||
}
|
||||
|
||||
impl Directive for RunDirective {
|
||||
fn from_action(action: &Action) -> Result<RunDirective> {
|
||||
let mut args_iter = action.args.iter();
|
||||
let mut envs = HashMap::new();
|
||||
let mut args = Vec::new();
|
||||
|
||||
let mut curr = args_iter.next();
|
||||
|
||||
while let Some((key, value)) = curr.and_then(|c| c.split_once('=')) {
|
||||
envs.insert(key.to_string(), value.to_string());
|
||||
curr = args_iter.next();
|
||||
}
|
||||
|
||||
let Some(arg0) = curr else {
|
||||
bail!("cannot determine arg0");
|
||||
};
|
||||
|
||||
for arg in args_iter {
|
||||
args.push(arg.to_string());
|
||||
}
|
||||
|
||||
let input = match &action.heredoc {
|
||||
Some(value) => Input::Content(value.to_string()),
|
||||
None => Input::None
|
||||
};
|
||||
|
||||
Ok(RunDirective {
|
||||
arg0: arg0.to_string(),
|
||||
args,
|
||||
envs,
|
||||
input
|
||||
})
|
||||
}
|
||||
|
||||
fn run_in_context(&self, context: &mut JailContext) -> Result<()> {
|
||||
let notify = EventFdNotify::new();
|
||||
/*
|
||||
let (stdout_a, stdout_b) = pipe()?;
|
||||
let (stderr_a, stderr_b) = pipe()?;
|
||||
let (stdin_a, stdin_b) = pipe()?;
|
||||
*/
|
||||
eprintln!("arg0: {}, args: {:?}", self.arg0, self.args);
|
||||
let request = ExecCommandRequest {
|
||||
name: context.container_id.clone().expect("container not set"),
|
||||
arg0: self.arg0.clone(),
|
||||
args: self.args.clone(),
|
||||
envs: self.envs.clone(),
|
||||
stdin: Maybe::None,//Maybe::Some(Fd(stdin_b)),
|
||||
stdout:Maybe::None,// Maybe::Some(Fd(stdout_b)),
|
||||
stderr:Maybe::None,// Maybe::Some(Fd(stderr_b)),
|
||||
uid: 0,
|
||||
notify: Maybe::Some(Fd(notify.as_raw_fd()))
|
||||
};
|
||||
eprintln!("before do_exec");
|
||||
match do_exec(&mut context.conn, request)? {
|
||||
Ok(_) => {
|
||||
eprintln!("before wait sync");
|
||||
notify.notified_sync();
|
||||
eprintln!("after wait sync");
|
||||
Ok(())
|
||||
},
|
||||
Err(err) => bail!("exec failure: {err:?}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,8 +24,10 @@
|
||||
pub mod directives;
|
||||
pub mod parse;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::os::unix::net::UnixStream;
|
||||
use tracing::error;
|
||||
use xcd::ipc::*;
|
||||
|
||||
pub(crate) struct JailContext {
|
||||
/// The current container we are operating in
|
||||
@@ -33,5 +35,33 @@ pub(crate) struct JailContext {
|
||||
/// Mapping to different containers for multi-stage build
|
||||
pub(crate) containers: HashMap<String, String>,
|
||||
|
||||
conn: UnixStream,
|
||||
pub(crate) conn: UnixStream,
|
||||
}
|
||||
|
||||
impl JailContext {
|
||||
pub(crate) fn new(conn: UnixStream) -> JailContext {
|
||||
JailContext {
|
||||
conn,
|
||||
container_id: None,
|
||||
containers: HashMap::new()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn release(mut self) -> anyhow::Result<()> {
|
||||
let mut containers = HashSet::new();
|
||||
if let Some(container) = self.container_id {
|
||||
containers.insert(container);
|
||||
}
|
||||
for (_, container) in self.containers.into_iter() {
|
||||
containers.insert(container);
|
||||
}
|
||||
for name in containers.into_iter() {
|
||||
let kill = KillContainerRequest { name: name.to_string() };
|
||||
match do_kill_container(&mut self.conn, kill)? {
|
||||
Ok(_) => {},
|
||||
Err(error) => { error!("cannot kill container {name}: {error:?}"); }
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,6 +82,9 @@ enum Action {
|
||||
Attach {
|
||||
name: String,
|
||||
},
|
||||
Build {
|
||||
image_reference: ImageReference
|
||||
},
|
||||
#[clap(subcommand)]
|
||||
Channel(ChannelAction),
|
||||
Commit {
|
||||
@@ -230,6 +233,51 @@ fn main() -> Result<(), ActionError> {
|
||||
}
|
||||
}
|
||||
}
|
||||
Action::Build { image_reference } => {
|
||||
use crate::jailfile::*;
|
||||
use crate::jailfile::parse::*;
|
||||
use crate::jailfile::directives::*;
|
||||
use crate::jailfile::directives::run::*;
|
||||
use crate::jailfile::directives::from::*;
|
||||
let file = std::fs::read_to_string("Jailfile")?;
|
||||
|
||||
let is_image_existed = do_describe_image(&mut conn, DescribeImageRequest {
|
||||
image_name: image_reference.name.to_string(),
|
||||
tag: image_reference.tag.to_string()
|
||||
})?;
|
||||
|
||||
if is_image_existed.is_ok() {
|
||||
Err(anyhow::anyhow!("image already exist"))?;
|
||||
}
|
||||
|
||||
let actions = parse_jailfile(&file)?;
|
||||
let mut context = JailContext::new(conn);
|
||||
|
||||
eprintln!("actions: {actions:#?}");
|
||||
|
||||
for action in actions.iter() {
|
||||
if action.directive_name == "RUN" {
|
||||
let directive = RunDirective::from_action(action)?;
|
||||
directive.run_in_context(&mut context)?;
|
||||
} else if action.directive_name == "FROM" {
|
||||
let directive = FromDirective::from_action(action)?;
|
||||
directive.run_in_context(&mut context)?;
|
||||
std::thread::sleep_ms(500);
|
||||
}
|
||||
}
|
||||
|
||||
let req = CommitRequest {
|
||||
name: image_reference.name,
|
||||
tag: image_reference.tag.to_string(),
|
||||
container_name: context.container_id.clone().unwrap(),
|
||||
};
|
||||
let response = do_commit_container(&mut context.conn, req)?.unwrap();
|
||||
eprintln!("{response:#?}");
|
||||
|
||||
context.release()?;
|
||||
// let response: CommitResponse = request(&mut conn, "commit", req)?;
|
||||
|
||||
}
|
||||
Action::Channel(action) => {
|
||||
use_channel_action(&mut conn, action)?;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user