preliminary RUN and FROM directive support, without network

This commit is contained in:
Yan Ka, Chiu
2023-07-09 18:47:05 -04:00
parent 9a01722657
commit ec36863235
5 changed files with 248 additions and 12 deletions

View File

@@ -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(())
}
}

View File

@@ -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>;
}

View File

@@ -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:?}")
}
}
}

View File

@@ -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(())
}
}

View File

@@ -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)?;
}