allow container to be reference by jid

This commit is contained in:
Yan Ka, Chiu
2023-07-06 01:21:22 +08:00
parent b2ed346c39
commit e1c445582b
7 changed files with 166 additions and 16 deletions

View File

@@ -25,12 +25,14 @@
use ipcidr::IpCidr;
use std::io::Write;
use std::net::IpAddr;
use std::process::Command;
use std::process::{Command, Stdio};
pub const PFCTL_CMD: &str = crate::env_or_default!("XC_PFCTL_CMD", "/sbin/pfctl");
pub fn is_pf_enabled() -> Result<bool, std::io::Error> {
Command::new(PFCTL_CMD)
.stdout(Stdio::null())
.stderr(Stdio::null())
.arg("-s")
.arg("Running")
.status()

View File

@@ -189,7 +189,7 @@ impl Container {
} else {
proto = proto.param("vnet", Value::Int(1));
for alloc in self.ip_alloc.iter() {
if let Some(network) = &alloc.network {
if let Some(_network) = &alloc.network {
let (epair_a, epair_b) = undo.create_epair()?;
undo.iface_up(epair_a.to_owned())?;
undo.iface_up(epair_b.to_owned())?;

View File

@@ -101,6 +101,20 @@ impl InstantiateBlueprint {
ipc::packet::codec::Maybe::Some(x) => Some(EventFdNotify::from_fd(x.as_raw_fd())),
};
for (name, env_spec) in config.envs.iter() {
if env_spec.required && !request.envs.contains_key(&name.to_string()) {
let extra_info = env_spec
.description
.as_ref()
.map(|d| format!(" - {d}"))
.unwrap_or_default();
precondition_failure!(
ENOENT,
"missing required environment variable: {name}{extra_info}"
);
}
}
let Some(entry_point) = config.entry_points.get(&request.entry_point) else {
precondition_failure!(ENOENT, "requested entry point not found: {}", request.entry_point);
};

View File

@@ -213,6 +213,15 @@ async fn instantiate(
// let id = Uuid::new_v4().to_string();
let id = gen_id();
if request
.name
.as_ref()
.and_then(|n| n.parse::<isize>().ok())
.is_some()
{
return ipc_err(EINVAL, "container name cannot be integer literal");
}
let row = {
let ctx = context.read().await;
let dlctx = ctx.image_manager.read().await;
@@ -526,27 +535,28 @@ async fn show_container(
}
#[derive(Serialize, Deserialize, Debug)]
pub struct DestroyContainerRequest {
pub struct KillContainerRequest {
pub name: String,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct DestroyContainerResponse {}
pub struct KillContainerResponse {}
#[ipc_method(method = "destroy_container")]
async fn destroy_container(
#[ipc_method(method = "kill_container")]
async fn kill_container(
context: Arc<RwLock<ServerContext>>,
local_context: &mut ConnectionContext<Variables>,
request: DestroyContainerRequest,
) -> GenericResult<DestroyContainerResponse> {
request: KillContainerRequest,
) -> GenericResult<KillContainerResponse> {
let mut context = context.write().await;
if let Some(id) = context.alias_map.get(&request.name).cloned() {
_ = context.terminate(&id).await;
Ok(DestroyContainerResponse {})
Ok(KillContainerResponse {})
} else {
enoent(format!("no such container: {}", request.name).as_str())
}
}
#[derive(Serialize, Deserialize, Debug)]
pub struct DoRdr {
pub name: String,
@@ -564,6 +574,25 @@ async fn rdr_container(
Ok(request)
}
#[derive(Serialize, Deserialize, Debug)]
pub struct ContainerRdrList {
pub name: String,
}
#[ipc_method(method = "list_site_rdr")]
async fn list_site_rdr(
context: Arc<RwLock<ServerContext>>,
local_context: &mut ConnectionContext<Variables>,
request: ContainerRdrList,
) -> GenericResult<Vec<PortRedirection>> {
let context = context.read().await;
if let Some(id) = context.alias_map.get(&request.name) {
Ok(context.port_forward_table.all_rules_with_id(id))
} else {
enoent(format!("no such container: {}", request.name).as_str())
}
}
#[derive(FromPacket)]
pub struct FdImport {
pub fd: Fd,
@@ -695,17 +724,17 @@ async fn commit_container(
}
#[derive(Serialize, Deserialize, Debug)]
pub struct ReplaceMetaRequest {
pub struct SetConfigRequest {
pub name: String,
pub tag: String,
pub meta: xc::models::jail_image::JailConfig,
pub config: xc::models::jail_image::JailConfig,
}
#[ipc_method(method = "replace_meta")]
async fn replace_meta(
context: Arc<RwLock<ServerContext>>,
local_context: &mut ConnectionContext<Variables>,
request: ReplaceMetaRequest,
request: SetConfigRequest,
) -> GenericResult<xc::models::jail_image::JailImage> {
let ctx = context.read().await;
let dlctx = ctx.image_manager.read().await;
@@ -714,7 +743,7 @@ async fn replace_meta(
.await
.unwrap();
let mut manifest = record.manifest;
manifest.set_config(&request.meta);
manifest.set_config(&request.config);
dlctx
.register_and_tag_manifest(&request.name, &request.tag, &manifest)
.await
@@ -860,7 +889,7 @@ pub(crate) async fn register_to_service(
service.register(create_network).await;
service.register(list_networks).await;
service.register(show_container).await;
service.register(destroy_container).await;
service.register(kill_container).await;
service.register(list_containers).await;
service.register(login_registry).await;
service.register(commit_container).await;

View File

@@ -31,6 +31,7 @@ mod port;
mod registry;
mod site;
mod task;
mod util;
pub mod ipc;
use config_manager::ConfigManager;

View File

@@ -29,6 +29,7 @@ use std::ffi::OsString;
use std::os::fd::RawFd;
use std::sync::Arc;
use tokio::sync::watch::Receiver;
use tracing::info;
use xc::config::XcConfig;
use xc::container::effect::UndoStack;
use xc::container::{Container, ContainerManifest};
@@ -110,7 +111,6 @@ impl Site {
pub fn kill_conatiner(&mut self) -> anyhow::Result<()> {
use freebsd::nix::sys::event::{kevent_ts, EventFilter, EventFlag, FilterFlag, KEvent};
use tracing::error;
let event = KEvent::new(
2,
EventFilter::EVFILT_USER,
@@ -119,7 +119,7 @@ impl Site {
0 as freebsd::libc::intptr_t,
0 as freebsd::libc::intptr_t,
);
error!("killing container");
info!("killing container");
_ = kevent_ts(self.ctl_channel.unwrap(), &[event], &mut [], None);
Ok(())
}

104
xcd/src/util.rs Normal file
View File

@@ -0,0 +1,104 @@
// 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 std::borrow::Borrow;
use std::collections::{HashMap, HashSet};
use std::hash::Hash;
pub struct TwoWayMap<K, V> {
reverse_map: HashMap<V, HashSet<K>>,
main_map: HashMap<K, V>,
}
impl<K, V> Default for TwoWayMap<K, V> {
fn default() -> TwoWayMap<K, V> {
TwoWayMap {
reverse_map: HashMap::new(),
main_map: HashMap::new(),
}
}
}
impl<K: Clone + Hash + Eq, V: Clone + Hash + Eq> TwoWayMap<K, V> {
pub fn new() -> TwoWayMap<K, V> {
TwoWayMap {
reverse_map: HashMap::new(),
main_map: HashMap::new(),
}
}
pub fn insert(&mut self, key: K, value: V) {
self.main_map.insert(key.clone(), value.clone());
match self.reverse_map.get_mut(&value) {
Some(vec) => {
vec.insert(key);
}
None => {
self.reverse_map
.insert(value.clone(), HashSet::from_iter([key]));
}
}
}
pub fn get<Q: Eq + Hash + ?Sized>(&self, key: &Q) -> Option<&V>
where
K: Borrow<Q>,
{
self.main_map.get(key)
}
#[allow(unused)]
pub fn contains_key<Q: Eq + Hash + ?Sized>(&self, key: &Q) -> Option<&V>
where
K: Borrow<Q>,
{
self.main_map.get(key)
}
pub fn remove_all_referenced<Q>(&mut self, value: &Q) -> Option<HashSet<K>>
where
V: Borrow<Q>,
Q: Eq + Hash + ?Sized,
{
let keys = self.reverse_map.remove(value)?;
for key in keys.iter() {
self.main_map.remove(key);
}
Some(keys)
}
#[allow(unused)]
pub fn remove<Q>(&mut self, key: &Q) -> Option<V>
where
K: Borrow<Q>,
Q: Eq + Hash + ?Sized,
{
let value = self.main_map.remove(key);
if let Some(value) = &value {
if let Some(keys) = self.reverse_map.get_mut(value) {
keys.remove(key);
}
}
value
}
}