mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-06-21 21:18:54 +00:00
agent: Add config for api-server-rest
Add configuration for 'rest api server'. Optional configurations are 'agent.rest_api=attestation' will enable attestation api 'agent.rest_api=resource' will enable resource api 'agent.rest_api=all' will enable all (attestation and resource) api Fixes: #7555 Signed-off-by: Biao Lu <biao.lu@intel.com> Signed-off-by: Fabiano Fidêncio <fabiano.fidencio@intel.com> Signed-off-by: Linda Yu <linda.yu@intel.com> Co-authored-by: stevenhorsman <steven@uk.ibm.com> Co-authored-by: Jakob Naucke <jakob.naucke@ibm.com> Co-authored-by: Wang, Arron <arron.wang@intel.com> Co-authored-by: zhouliang121 <liang.a.zhou@linux.alibaba.com> Co-authored-by: Alex Carter <alex.carter@ibm.com> Co-authored-by: Suraj Deshmukh <suraj.deshmukh@microsoft.com> Co-authored-by: Xynnn007 <xynnn@linux.alibaba.com>
This commit is contained in:
parent
f476d671ed
commit
4d752e6350
@ -70,6 +70,8 @@ vsock-exporter = { path = "vsock-exporter" }
|
|||||||
serde = { version = "1.0.129", features = ["derive"] }
|
serde = { version = "1.0.129", features = ["derive"] }
|
||||||
toml = "0.5.8"
|
toml = "0.5.8"
|
||||||
clap = { version = "3.0.1", features = ["derive"] }
|
clap = { version = "3.0.1", features = ["derive"] }
|
||||||
|
strum = "0.26.2"
|
||||||
|
strum_macros = "0.26.2"
|
||||||
|
|
||||||
# Communication with the OPA service
|
# Communication with the OPA service
|
||||||
http = { version = "0.2.8", optional = true }
|
http = { version = "0.2.8", optional = true }
|
||||||
|
@ -3,12 +3,13 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
//
|
//
|
||||||
use crate::rpc;
|
use crate::rpc;
|
||||||
use anyhow::{bail, ensure, Context, Result};
|
use anyhow::{anyhow, bail, ensure, Context, Result};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::time;
|
use std::time;
|
||||||
|
use strum_macros::{Display, EnumString};
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
@ -26,6 +27,7 @@ const LOG_VPORT_OPTION: &str = "agent.log_vport";
|
|||||||
const CONTAINER_PIPE_SIZE_OPTION: &str = "agent.container_pipe_size";
|
const CONTAINER_PIPE_SIZE_OPTION: &str = "agent.container_pipe_size";
|
||||||
const UNIFIED_CGROUP_HIERARCHY_OPTION: &str = "systemd.unified_cgroup_hierarchy";
|
const UNIFIED_CGROUP_HIERARCHY_OPTION: &str = "systemd.unified_cgroup_hierarchy";
|
||||||
const CONFIG_FILE: &str = "agent.config_file";
|
const CONFIG_FILE: &str = "agent.config_file";
|
||||||
|
const REST_API_OPTION: &str = "agent.guest_components_rest_api";
|
||||||
|
|
||||||
// Configure the proxy settings for HTTPS requests in the guest,
|
// Configure the proxy settings for HTTPS requests in the guest,
|
||||||
// to solve the problem of not being able to access the specified image in some cases.
|
// to solve the problem of not being able to access the specified image in some cases.
|
||||||
@ -48,7 +50,6 @@ const ERR_INVALID_GET_VALUE_PARAM: &str = "expected name=value";
|
|||||||
const ERR_INVALID_GET_VALUE_NO_NAME: &str = "name=value parameter missing name";
|
const ERR_INVALID_GET_VALUE_NO_NAME: &str = "name=value parameter missing name";
|
||||||
const ERR_INVALID_GET_VALUE_NO_VALUE: &str = "name=value parameter missing value";
|
const ERR_INVALID_GET_VALUE_NO_VALUE: &str = "name=value parameter missing value";
|
||||||
const ERR_INVALID_LOG_LEVEL_KEY: &str = "invalid log level key name";
|
const ERR_INVALID_LOG_LEVEL_KEY: &str = "invalid log level key name";
|
||||||
|
|
||||||
const ERR_INVALID_HOTPLUG_TIMEOUT: &str = "invalid hotplug timeout parameter";
|
const ERR_INVALID_HOTPLUG_TIMEOUT: &str = "invalid hotplug timeout parameter";
|
||||||
const ERR_INVALID_HOTPLUG_TIMEOUT_PARAM: &str = "unable to parse hotplug timeout";
|
const ERR_INVALID_HOTPLUG_TIMEOUT_PARAM: &str = "unable to parse hotplug timeout";
|
||||||
const ERR_INVALID_HOTPLUG_TIMEOUT_KEY: &str = "invalid hotplug timeout key name";
|
const ERR_INVALID_HOTPLUG_TIMEOUT_KEY: &str = "invalid hotplug timeout key name";
|
||||||
@ -58,6 +59,19 @@ const ERR_INVALID_CONTAINER_PIPE_SIZE_PARAM: &str = "unable to parse container p
|
|||||||
const ERR_INVALID_CONTAINER_PIPE_SIZE_KEY: &str = "invalid container pipe size key name";
|
const ERR_INVALID_CONTAINER_PIPE_SIZE_KEY: &str = "invalid container pipe size key name";
|
||||||
const ERR_INVALID_CONTAINER_PIPE_NEGATIVE: &str = "container pipe size should not be negative";
|
const ERR_INVALID_CONTAINER_PIPE_NEGATIVE: &str = "container pipe size should not be negative";
|
||||||
|
|
||||||
|
const ERR_INVALID_GUEST_COMPONENTS_REST_API_VALUE: &str = "invalid guest components rest api feature given. Valid values are `all`, `attestation`, `resource`, or `none`";
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Default, Display, Deserialize, EnumString, PartialEq)]
|
||||||
|
// Features seem to typically be in kebab-case format, but we only have single words at the moment
|
||||||
|
#[strum(serialize_all = "kebab-case")]
|
||||||
|
pub enum GuestComponentsFeatures {
|
||||||
|
All,
|
||||||
|
Attestation,
|
||||||
|
None,
|
||||||
|
#[default]
|
||||||
|
Resource,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct AgentConfig {
|
pub struct AgentConfig {
|
||||||
pub debug_console: bool,
|
pub debug_console: bool,
|
||||||
@ -74,6 +88,7 @@ pub struct AgentConfig {
|
|||||||
pub supports_seccomp: bool,
|
pub supports_seccomp: bool,
|
||||||
pub https_proxy: String,
|
pub https_proxy: String,
|
||||||
pub no_proxy: String,
|
pub no_proxy: String,
|
||||||
|
pub guest_components_rest_api: GuestComponentsFeatures,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
@ -91,6 +106,7 @@ pub struct AgentConfigBuilder {
|
|||||||
pub tracing: Option<bool>,
|
pub tracing: Option<bool>,
|
||||||
pub https_proxy: Option<String>,
|
pub https_proxy: Option<String>,
|
||||||
pub no_proxy: Option<String>,
|
pub no_proxy: Option<String>,
|
||||||
|
pub guest_components_rest_api: Option<GuestComponentsFeatures>,
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! config_override {
|
macro_rules! config_override {
|
||||||
@ -154,6 +170,7 @@ impl Default for AgentConfig {
|
|||||||
supports_seccomp: rpc::have_seccomp(),
|
supports_seccomp: rpc::have_seccomp(),
|
||||||
https_proxy: String::from(""),
|
https_proxy: String::from(""),
|
||||||
no_proxy: String::from(""),
|
no_proxy: String::from(""),
|
||||||
|
guest_components_rest_api: GuestComponentsFeatures::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -185,6 +202,11 @@ impl FromStr for AgentConfig {
|
|||||||
config_override!(agent_config_builder, agent_config, tracing);
|
config_override!(agent_config_builder, agent_config, tracing);
|
||||||
config_override!(agent_config_builder, agent_config, https_proxy);
|
config_override!(agent_config_builder, agent_config, https_proxy);
|
||||||
config_override!(agent_config_builder, agent_config, no_proxy);
|
config_override!(agent_config_builder, agent_config, no_proxy);
|
||||||
|
config_override!(
|
||||||
|
agent_config_builder,
|
||||||
|
agent_config,
|
||||||
|
guest_components_rest_api
|
||||||
|
);
|
||||||
|
|
||||||
Ok(agent_config)
|
Ok(agent_config)
|
||||||
}
|
}
|
||||||
@ -286,6 +308,12 @@ impl AgentConfig {
|
|||||||
);
|
);
|
||||||
parse_cmdline_param!(param, HTTPS_PROXY, config.https_proxy, get_url_value);
|
parse_cmdline_param!(param, HTTPS_PROXY, config.https_proxy, get_url_value);
|
||||||
parse_cmdline_param!(param, NO_PROXY, config.no_proxy, get_string_value);
|
parse_cmdline_param!(param, NO_PROXY, config.no_proxy, get_string_value);
|
||||||
|
parse_cmdline_param!(
|
||||||
|
param,
|
||||||
|
REST_API_OPTION,
|
||||||
|
config.guest_components_rest_api,
|
||||||
|
get_guest_components_features_value
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(addr) = env::var(SERVER_ADDR_ENV_VAR) {
|
if let Ok(addr) = env::var(SERVER_ADDR_ENV_VAR) {
|
||||||
@ -439,6 +467,19 @@ fn get_url_value(param: &str) -> Result<String> {
|
|||||||
Ok(Url::parse(&value)?.to_string())
|
Ok(Url::parse(&value)?.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument]
|
||||||
|
fn get_guest_components_features_value(param: &str) -> Result<GuestComponentsFeatures> {
|
||||||
|
let fields: Vec<&str> = param.split('=').collect();
|
||||||
|
ensure!(fields.len() >= 2, ERR_INVALID_GET_VALUE_PARAM);
|
||||||
|
|
||||||
|
// We need name (but the value can be blank)
|
||||||
|
ensure!(!fields[0].is_empty(), ERR_INVALID_GET_VALUE_NO_NAME);
|
||||||
|
|
||||||
|
let value = fields[1..].join("=");
|
||||||
|
GuestComponentsFeatures::from_str(&value)
|
||||||
|
.map_err(|_| anyhow!(ERR_INVALID_GUEST_COMPONENTS_REST_API_VALUE))
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use test_utils::assert_result;
|
use test_utils::assert_result;
|
||||||
@ -477,6 +518,7 @@ mod tests {
|
|||||||
tracing: bool,
|
tracing: bool,
|
||||||
https_proxy: &'a str,
|
https_proxy: &'a str,
|
||||||
no_proxy: &'a str,
|
no_proxy: &'a str,
|
||||||
|
guest_components_rest_api: GuestComponentsFeatures,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for TestData<'_> {
|
impl Default for TestData<'_> {
|
||||||
@ -494,6 +536,7 @@ mod tests {
|
|||||||
tracing: false,
|
tracing: false,
|
||||||
https_proxy: "",
|
https_proxy: "",
|
||||||
no_proxy: "",
|
no_proxy: "",
|
||||||
|
guest_components_rest_api: GuestComponentsFeatures::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -883,6 +926,26 @@ mod tests {
|
|||||||
no_proxy: "192.168.1.0/24,172.16.0.0/12",
|
no_proxy: "192.168.1.0/24,172.16.0.0/12",
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
TestData {
|
||||||
|
contents: "agent.guest_components_rest_api=attestation",
|
||||||
|
guest_components_rest_api: GuestComponentsFeatures::Attestation,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
contents: "agent.guest_components_rest_api=resource",
|
||||||
|
guest_components_rest_api: GuestComponentsFeatures::Resource,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
contents: "agent.guest_components_rest_api=all",
|
||||||
|
guest_components_rest_api: GuestComponentsFeatures::All,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
contents: "agent.guest_components_rest_api=none",
|
||||||
|
guest_components_rest_api: GuestComponentsFeatures::None,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
let dir = tempdir().expect("failed to create tmpdir");
|
let dir = tempdir().expect("failed to create tmpdir");
|
||||||
@ -932,6 +995,11 @@ mod tests {
|
|||||||
assert_eq!(d.tracing, config.tracing, "{}", msg);
|
assert_eq!(d.tracing, config.tracing, "{}", msg);
|
||||||
assert_eq!(d.https_proxy, config.https_proxy, "{}", msg);
|
assert_eq!(d.https_proxy, config.https_proxy, "{}", msg);
|
||||||
assert_eq!(d.no_proxy, config.no_proxy, "{}", msg);
|
assert_eq!(d.no_proxy, config.no_proxy, "{}", msg);
|
||||||
|
assert_eq!(
|
||||||
|
d.guest_components_rest_api, config.guest_components_rest_api,
|
||||||
|
"{}",
|
||||||
|
msg
|
||||||
|
);
|
||||||
|
|
||||||
for v in vars_to_unset {
|
for v in vars_to_unset {
|
||||||
env::remove_var(v);
|
env::remove_var(v);
|
||||||
@ -1403,6 +1471,68 @@ Caused by:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_get_guest_components_features_value() {
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct TestData<'a> {
|
||||||
|
param: &'a str,
|
||||||
|
result: Result<GuestComponentsFeatures>,
|
||||||
|
}
|
||||||
|
|
||||||
|
let tests = &[
|
||||||
|
TestData {
|
||||||
|
param: "",
|
||||||
|
result: Err(anyhow!(ERR_INVALID_GET_VALUE_PARAM)),
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
param: "=",
|
||||||
|
result: Err(anyhow!(ERR_INVALID_GET_VALUE_NO_NAME)),
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
param: "==",
|
||||||
|
result: Err(anyhow!(ERR_INVALID_GET_VALUE_NO_NAME)),
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
param: "x=all",
|
||||||
|
result: Ok(GuestComponentsFeatures::All),
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
param: "x=attestation",
|
||||||
|
result: Ok(GuestComponentsFeatures::Attestation),
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
param: "x=none",
|
||||||
|
result: Ok(GuestComponentsFeatures::None),
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
param: "x=resource",
|
||||||
|
result: Ok(GuestComponentsFeatures::Resource),
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
param: "x===",
|
||||||
|
result: Err(anyhow!(ERR_INVALID_GUEST_COMPONENTS_REST_API_VALUE)),
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
param: "x==x",
|
||||||
|
result: Err(anyhow!(ERR_INVALID_GUEST_COMPONENTS_REST_API_VALUE)),
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
param: "x=x",
|
||||||
|
result: Err(anyhow!(ERR_INVALID_GUEST_COMPONENTS_REST_API_VALUE)),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
for (i, d) in tests.iter().enumerate() {
|
||||||
|
let msg = format!("test[{}]: {:?}", i, d);
|
||||||
|
|
||||||
|
let result = get_guest_components_features_value(d.param);
|
||||||
|
|
||||||
|
let msg = format!("{}: result: {:?}", msg, result);
|
||||||
|
|
||||||
|
assert_result!(d.result, result, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_config_builder_from_string() {
|
fn test_config_builder_from_string() {
|
||||||
let config = AgentConfig::from_str(
|
let config = AgentConfig::from_str(
|
||||||
|
Loading…
Reference in New Issue
Block a user