mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2025-03-20 07:58:55 +00:00
ch-remote, api_client: Split HTTP/API client code into new crate
Split out the HTTP request handling code from ch-remote into a new crate which can be used in other places where talking to the API server by HTTP is necessary. Signed-off-by: Rob Bradford <robert.bradford@intel.com>
This commit is contained in:
parent
654846f433
commit
8de3bd728c
5
Cargo.lock
generated
5
Cargo.lock
generated
@ -46,6 +46,10 @@ version = "1.0.33"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a1fd36ffbb1fb7c834eac128ea8d0e310c5aeb635548f9d58861e1308d46e71c"
|
checksum = "a1fd36ffbb1fb7c834eac128ea8d0e310c5aeb635548f9d58861e1308d46e71c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "api_client"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arc-swap"
|
name = "arc-swap"
|
||||||
version = "0.4.7"
|
version = "0.4.7"
|
||||||
@ -208,6 +212,7 @@ dependencies = [
|
|||||||
name = "cloud-hypervisor"
|
name = "cloud-hypervisor"
|
||||||
version = "0.10.0"
|
version = "0.10.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"api_client",
|
||||||
"clap",
|
"clap",
|
||||||
"credibility",
|
"credibility",
|
||||||
"dirs",
|
"dirs",
|
||||||
|
@ -13,6 +13,7 @@ homepage = "https://github.com/cloud-hypervisor/cloud-hypervisor"
|
|||||||
lto = true
|
lto = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
api_client = { path = "api_client" }
|
||||||
clap = { version = "2.33.3", features = ["wrap_help"] }
|
clap = { version = "2.33.3", features = ["wrap_help"] }
|
||||||
hypervisor = { path = "hypervisor" }
|
hypervisor = { path = "hypervisor" }
|
||||||
libc = "0.2.79"
|
libc = "0.2.79"
|
||||||
@ -62,6 +63,7 @@ integration_tests = []
|
|||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
"acpi_tables",
|
"acpi_tables",
|
||||||
|
"api_client",
|
||||||
"arch",
|
"arch",
|
||||||
"arch_gen",
|
"arch_gen",
|
||||||
"block_util",
|
"block_util",
|
||||||
|
5
api_client/Cargo.toml
Normal file
5
api_client/Cargo.toml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
[package]
|
||||||
|
name = "api_client"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["The Cloud Hypervisor Authors"]
|
||||||
|
edition = "2018"
|
175
api_client/src/lib.rs
Normal file
175
api_client/src/lib.rs
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
// Copyright © 2020 Intel Corporation
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
use std::io::{Read, Write};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
Socket(std::io::Error),
|
||||||
|
StatusCodeParsing(std::num::ParseIntError),
|
||||||
|
MissingProtocol,
|
||||||
|
ContentLengthParsing(std::num::ParseIntError),
|
||||||
|
ServerResponse(StatusCode, Option<String>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Error {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
use Error::*;
|
||||||
|
match self {
|
||||||
|
Socket(e) => write!(f, "Error writing to or reading from HTTP socket: {}", e),
|
||||||
|
StatusCodeParsing(e) => write!(f, "Error parsing HTTP status code: {}", e),
|
||||||
|
MissingProtocol => write!(f, "HTTP output is missing protocol statement"),
|
||||||
|
ContentLengthParsing(e) => write!(f, "Error parsing HTTP Content-Length field: {}", e),
|
||||||
|
ServerResponse(s, o) => {
|
||||||
|
if let Some(o) = o {
|
||||||
|
write!(f, "Server responded with an error: {:?}: {}", s, o)
|
||||||
|
} else {
|
||||||
|
write!(f, "Server responded with an error: {:?}", s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub enum StatusCode {
|
||||||
|
Continue,
|
||||||
|
OK,
|
||||||
|
NoContent,
|
||||||
|
BadRequest,
|
||||||
|
NotFound,
|
||||||
|
InternalServerError,
|
||||||
|
NotImplemented,
|
||||||
|
Unknown,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StatusCode {
|
||||||
|
fn from_raw(code: usize) -> StatusCode {
|
||||||
|
match code {
|
||||||
|
100 => StatusCode::Continue,
|
||||||
|
200 => StatusCode::OK,
|
||||||
|
204 => StatusCode::NoContent,
|
||||||
|
400 => StatusCode::BadRequest,
|
||||||
|
404 => StatusCode::NotFound,
|
||||||
|
500 => StatusCode::InternalServerError,
|
||||||
|
501 => StatusCode::NotImplemented,
|
||||||
|
_ => StatusCode::Unknown,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse(code: &str) -> Result<StatusCode, Error> {
|
||||||
|
Ok(StatusCode::from_raw(
|
||||||
|
code.trim().parse().map_err(Error::StatusCodeParsing)?,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_server_error(self) -> bool {
|
||||||
|
!matches!(
|
||||||
|
self,
|
||||||
|
StatusCode::OK | StatusCode::Continue | StatusCode::NoContent
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_header<'a>(res: &'a str, header: &'a str) -> Option<&'a str> {
|
||||||
|
let header_str = format!("{}: ", header);
|
||||||
|
if let Some(o) = res.find(&header_str) {
|
||||||
|
Some(&res[o + header_str.len()..o + res[o..].find('\r').unwrap()])
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_status_code(res: &str) -> Result<StatusCode, Error> {
|
||||||
|
if let Some(o) = res.find("HTTP/1.1") {
|
||||||
|
Ok(StatusCode::parse(
|
||||||
|
&res[o + "HTTP/1.1 ".len()..res[o..].find('\r').unwrap()],
|
||||||
|
)?)
|
||||||
|
} else {
|
||||||
|
Err(Error::MissingProtocol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_http_response(socket: &mut dyn Read) -> Result<Option<String>, Error> {
|
||||||
|
let mut res = String::new();
|
||||||
|
let mut body_offset = None;
|
||||||
|
let mut content_length: Option<usize> = None;
|
||||||
|
loop {
|
||||||
|
let mut bytes = vec![0; 256];
|
||||||
|
let count = socket.read(&mut bytes).map_err(Error::Socket)?;
|
||||||
|
res.push_str(std::str::from_utf8(&bytes[0..count]).unwrap());
|
||||||
|
|
||||||
|
// End of headers
|
||||||
|
if let Some(o) = res.find("\r\n\r\n") {
|
||||||
|
body_offset = Some(o + "\r\n\r\n".len());
|
||||||
|
|
||||||
|
// With all headers available we can see if there is any body
|
||||||
|
content_length = if let Some(length) = get_header(&res, "Content-Length") {
|
||||||
|
Some(length.trim().parse().map_err(Error::ContentLengthParsing)?)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
if content_length.is_none() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(body_offset) = body_offset {
|
||||||
|
if let Some(content_length) = content_length {
|
||||||
|
if res.len() >= content_length + body_offset {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let body_string = content_length.and(Some(String::from(&res[body_offset.unwrap()..])));
|
||||||
|
let status_code = get_status_code(&res)?;
|
||||||
|
|
||||||
|
if status_code.is_server_error() {
|
||||||
|
Err(Error::ServerResponse(status_code, body_string))
|
||||||
|
} else {
|
||||||
|
Ok(body_string)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn simple_api_command<T: Read + Write>(
|
||||||
|
socket: &mut T,
|
||||||
|
method: &str,
|
||||||
|
c: &str,
|
||||||
|
request_body: Option<&str>,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
socket
|
||||||
|
.write_all(
|
||||||
|
format!(
|
||||||
|
"{} /api/v1/vm.{} HTTP/1.1\r\nHost: localhost\r\nAccept: */*\r\n",
|
||||||
|
method, c
|
||||||
|
)
|
||||||
|
.as_bytes(),
|
||||||
|
)
|
||||||
|
.map_err(Error::Socket)?;
|
||||||
|
|
||||||
|
if let Some(request_body) = request_body {
|
||||||
|
socket
|
||||||
|
.write_all(format!("Content-Length: {}\r\n", request_body.len()).as_bytes())
|
||||||
|
.map_err(Error::Socket)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.write_all(b"\r\n").map_err(Error::Socket)?;
|
||||||
|
|
||||||
|
if let Some(request_body) = request_body {
|
||||||
|
socket
|
||||||
|
.write_all(request_body.as_bytes())
|
||||||
|
.map_err(Error::Socket)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.flush().map_err(Error::Socket)?;
|
||||||
|
|
||||||
|
if let Some(body) = parse_http_response(socket)? {
|
||||||
|
println!("{}", body);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
@ -5,23 +5,22 @@
|
|||||||
|
|
||||||
#[macro_use(crate_authors)]
|
#[macro_use(crate_authors)]
|
||||||
extern crate clap;
|
extern crate clap;
|
||||||
|
extern crate api_client;
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
extern crate vmm;
|
extern crate vmm;
|
||||||
|
|
||||||
|
use api_client::simple_api_command;
|
||||||
|
use api_client::Error as ApiClientError;
|
||||||
use clap::{App, AppSettings, Arg, ArgMatches, SubCommand};
|
use clap::{App, AppSettings, Arg, ArgMatches, SubCommand};
|
||||||
use option_parser::{ByteSized, ByteSizedParseError};
|
use option_parser::{ByteSized, ByteSizedParseError};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io::{Read, Write};
|
|
||||||
use std::os::unix::net::UnixStream;
|
use std::os::unix::net::UnixStream;
|
||||||
use std::process;
|
use std::process;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum Error {
|
enum Error {
|
||||||
Socket(std::io::Error),
|
Connect(std::io::Error),
|
||||||
StatusCodeParsing(std::num::ParseIntError),
|
ApiClient(ApiClientError),
|
||||||
MissingProtocol,
|
|
||||||
ContentLengthParsing(std::num::ParseIntError),
|
|
||||||
ServerResponse(StatusCode, Option<String>),
|
|
||||||
InvalidCPUCount(std::num::ParseIntError),
|
InvalidCPUCount(std::num::ParseIntError),
|
||||||
InvalidMemorySize(ByteSizedParseError),
|
InvalidMemorySize(ByteSizedParseError),
|
||||||
InvalidBalloonSize(ByteSizedParseError),
|
InvalidBalloonSize(ByteSizedParseError),
|
||||||
@ -38,17 +37,8 @@ impl fmt::Display for Error {
|
|||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
use Error::*;
|
use Error::*;
|
||||||
match self {
|
match self {
|
||||||
Socket(e) => write!(f, "Error writing to HTTP socket: {}", e),
|
ApiClient(e) => e.fmt(f),
|
||||||
StatusCodeParsing(e) => write!(f, "Error parsing HTTP status code: {}", e),
|
Connect(e) => write!(f, "Error openning HTTP socket: {}", e),
|
||||||
MissingProtocol => write!(f, "HTTP output is missing protocol statement"),
|
|
||||||
ContentLengthParsing(e) => write!(f, "Error parsing HTTP Content-Length field: {}", e),
|
|
||||||
ServerResponse(s, o) => {
|
|
||||||
if let Some(o) = o {
|
|
||||||
write!(f, "Server responded with an error: {:?}: {}", s, o)
|
|
||||||
} else {
|
|
||||||
write!(f, "Server responded with an error: {:?}", s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
InvalidCPUCount(e) => write!(f, "Error parsing CPU count: {}", e),
|
InvalidCPUCount(e) => write!(f, "Error parsing CPU count: {}", e),
|
||||||
InvalidMemorySize(e) => write!(f, "Error parsing memory size: {:?}", e),
|
InvalidMemorySize(e) => write!(f, "Error parsing memory size: {:?}", e),
|
||||||
InvalidBalloonSize(e) => write!(f, "Error parsing balloon size: {:?}", e),
|
InvalidBalloonSize(e) => write!(f, "Error parsing balloon size: {:?}", e),
|
||||||
@ -63,146 +53,6 @@ impl fmt::Display for Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
|
||||||
pub enum StatusCode {
|
|
||||||
Continue,
|
|
||||||
OK,
|
|
||||||
NoContent,
|
|
||||||
BadRequest,
|
|
||||||
NotFound,
|
|
||||||
InternalServerError,
|
|
||||||
NotImplemented,
|
|
||||||
Unknown,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StatusCode {
|
|
||||||
fn from_raw(code: usize) -> StatusCode {
|
|
||||||
match code {
|
|
||||||
100 => StatusCode::Continue,
|
|
||||||
200 => StatusCode::OK,
|
|
||||||
204 => StatusCode::NoContent,
|
|
||||||
400 => StatusCode::BadRequest,
|
|
||||||
404 => StatusCode::NotFound,
|
|
||||||
500 => StatusCode::InternalServerError,
|
|
||||||
501 => StatusCode::NotImplemented,
|
|
||||||
_ => StatusCode::Unknown,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse(code: &str) -> Result<StatusCode, Error> {
|
|
||||||
Ok(StatusCode::from_raw(
|
|
||||||
code.trim().parse().map_err(Error::StatusCodeParsing)?,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_server_error(self) -> bool {
|
|
||||||
!matches!(
|
|
||||||
self,
|
|
||||||
StatusCode::OK | StatusCode::Continue | StatusCode::NoContent
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_header<'a>(res: &'a str, header: &'a str) -> Option<&'a str> {
|
|
||||||
let header_str = format!("{}: ", header);
|
|
||||||
if let Some(o) = res.find(&header_str) {
|
|
||||||
Some(&res[o + header_str.len()..o + res[o..].find('\r').unwrap()])
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_status_code(res: &str) -> Result<StatusCode, Error> {
|
|
||||||
if let Some(o) = res.find("HTTP/1.1") {
|
|
||||||
Ok(StatusCode::parse(
|
|
||||||
&res[o + "HTTP/1.1 ".len()..res[o..].find('\r').unwrap()],
|
|
||||||
)?)
|
|
||||||
} else {
|
|
||||||
Err(Error::MissingProtocol)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_http_response(socket: &mut dyn Read) -> Result<Option<String>, Error> {
|
|
||||||
let mut res = String::new();
|
|
||||||
let mut body_offset = None;
|
|
||||||
let mut content_length: Option<usize> = None;
|
|
||||||
loop {
|
|
||||||
let mut bytes = vec![0; 256];
|
|
||||||
let count = socket.read(&mut bytes).map_err(Error::Socket)?;
|
|
||||||
res.push_str(std::str::from_utf8(&bytes[0..count]).unwrap());
|
|
||||||
|
|
||||||
// End of headers
|
|
||||||
if let Some(o) = res.find("\r\n\r\n") {
|
|
||||||
body_offset = Some(o + "\r\n\r\n".len());
|
|
||||||
|
|
||||||
// With all headers available we can see if there is any body
|
|
||||||
content_length = if let Some(length) = get_header(&res, "Content-Length") {
|
|
||||||
Some(length.trim().parse().map_err(Error::ContentLengthParsing)?)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
if content_length.is_none() {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(body_offset) = body_offset {
|
|
||||||
if let Some(content_length) = content_length {
|
|
||||||
if res.len() >= content_length + body_offset {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let body_string = content_length.and(Some(String::from(&res[body_offset.unwrap()..])));
|
|
||||||
let status_code = get_status_code(&res)?;
|
|
||||||
|
|
||||||
if status_code.is_server_error() {
|
|
||||||
Err(Error::ServerResponse(status_code, body_string))
|
|
||||||
} else {
|
|
||||||
Ok(body_string)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn simple_api_command<T: Read + Write>(
|
|
||||||
socket: &mut T,
|
|
||||||
method: &str,
|
|
||||||
c: &str,
|
|
||||||
request_body: Option<&str>,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
socket
|
|
||||||
.write_all(
|
|
||||||
format!(
|
|
||||||
"{} /api/v1/vm.{} HTTP/1.1\r\nHost: localhost\r\nAccept: */*\r\n",
|
|
||||||
method, c
|
|
||||||
)
|
|
||||||
.as_bytes(),
|
|
||||||
)
|
|
||||||
.map_err(Error::Socket)?;
|
|
||||||
|
|
||||||
if let Some(request_body) = request_body {
|
|
||||||
socket
|
|
||||||
.write_all(format!("Content-Length: {}\r\n", request_body.len()).as_bytes())
|
|
||||||
.map_err(Error::Socket)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
socket.write_all(b"\r\n").map_err(Error::Socket)?;
|
|
||||||
|
|
||||||
if let Some(request_body) = request_body {
|
|
||||||
socket
|
|
||||||
.write_all(request_body.as_bytes())
|
|
||||||
.map_err(Error::Socket)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
socket.flush().map_err(Error::Socket)?;
|
|
||||||
|
|
||||||
if let Some(body) = parse_http_response(socket)? {
|
|
||||||
println!("{}", body);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resize_api_command(
|
fn resize_api_command(
|
||||||
socket: &mut UnixStream,
|
socket: &mut UnixStream,
|
||||||
cpus: Option<&str>,
|
cpus: Option<&str>,
|
||||||
@ -249,6 +99,7 @@ fn resize_api_command(
|
|||||||
"resize",
|
"resize",
|
||||||
Some(&serde_json::to_string(&resize).unwrap()),
|
Some(&serde_json::to_string(&resize).unwrap()),
|
||||||
)
|
)
|
||||||
|
.map_err(Error::ApiClient)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resize_zone_api_command(socket: &mut UnixStream, id: &str, size: &str) -> Result<(), Error> {
|
fn resize_zone_api_command(socket: &mut UnixStream, id: &str, size: &str) -> Result<(), Error> {
|
||||||
@ -266,6 +117,7 @@ fn resize_zone_api_command(socket: &mut UnixStream, id: &str, size: &str) -> Res
|
|||||||
"resize-zone",
|
"resize-zone",
|
||||||
Some(&serde_json::to_string(&resize_zone).unwrap()),
|
Some(&serde_json::to_string(&resize_zone).unwrap()),
|
||||||
)
|
)
|
||||||
|
.map_err(Error::ApiClient)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_device_api_command(socket: &mut UnixStream, config: &str) -> Result<(), Error> {
|
fn add_device_api_command(socket: &mut UnixStream, config: &str) -> Result<(), Error> {
|
||||||
@ -277,6 +129,7 @@ fn add_device_api_command(socket: &mut UnixStream, config: &str) -> Result<(), E
|
|||||||
"add-device",
|
"add-device",
|
||||||
Some(&serde_json::to_string(&device_config).unwrap()),
|
Some(&serde_json::to_string(&device_config).unwrap()),
|
||||||
)
|
)
|
||||||
|
.map_err(Error::ApiClient)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_device_api_command(socket: &mut UnixStream, id: &str) -> Result<(), Error> {
|
fn remove_device_api_command(socket: &mut UnixStream, id: &str) -> Result<(), Error> {
|
||||||
@ -288,6 +141,7 @@ fn remove_device_api_command(socket: &mut UnixStream, id: &str) -> Result<(), Er
|
|||||||
"remove-device",
|
"remove-device",
|
||||||
Some(&serde_json::to_string(&remove_device_data).unwrap()),
|
Some(&serde_json::to_string(&remove_device_data).unwrap()),
|
||||||
)
|
)
|
||||||
|
.map_err(Error::ApiClient)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_disk_api_command(socket: &mut UnixStream, config: &str) -> Result<(), Error> {
|
fn add_disk_api_command(socket: &mut UnixStream, config: &str) -> Result<(), Error> {
|
||||||
@ -299,6 +153,7 @@ fn add_disk_api_command(socket: &mut UnixStream, config: &str) -> Result<(), Err
|
|||||||
"add-disk",
|
"add-disk",
|
||||||
Some(&serde_json::to_string(&disk_config).unwrap()),
|
Some(&serde_json::to_string(&disk_config).unwrap()),
|
||||||
)
|
)
|
||||||
|
.map_err(Error::ApiClient)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_fs_api_command(socket: &mut UnixStream, config: &str) -> Result<(), Error> {
|
fn add_fs_api_command(socket: &mut UnixStream, config: &str) -> Result<(), Error> {
|
||||||
@ -310,6 +165,7 @@ fn add_fs_api_command(socket: &mut UnixStream, config: &str) -> Result<(), Error
|
|||||||
"add-fs",
|
"add-fs",
|
||||||
Some(&serde_json::to_string(&fs_config).unwrap()),
|
Some(&serde_json::to_string(&fs_config).unwrap()),
|
||||||
)
|
)
|
||||||
|
.map_err(Error::ApiClient)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_pmem_api_command(socket: &mut UnixStream, config: &str) -> Result<(), Error> {
|
fn add_pmem_api_command(socket: &mut UnixStream, config: &str) -> Result<(), Error> {
|
||||||
@ -321,6 +177,7 @@ fn add_pmem_api_command(socket: &mut UnixStream, config: &str) -> Result<(), Err
|
|||||||
"add-pmem",
|
"add-pmem",
|
||||||
Some(&serde_json::to_string(&pmem_config).unwrap()),
|
Some(&serde_json::to_string(&pmem_config).unwrap()),
|
||||||
)
|
)
|
||||||
|
.map_err(Error::ApiClient)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_net_api_command(socket: &mut UnixStream, config: &str) -> Result<(), Error> {
|
fn add_net_api_command(socket: &mut UnixStream, config: &str) -> Result<(), Error> {
|
||||||
@ -332,6 +189,7 @@ fn add_net_api_command(socket: &mut UnixStream, config: &str) -> Result<(), Erro
|
|||||||
"add-net",
|
"add-net",
|
||||||
Some(&serde_json::to_string(&net_config).unwrap()),
|
Some(&serde_json::to_string(&net_config).unwrap()),
|
||||||
)
|
)
|
||||||
|
.map_err(Error::ApiClient)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_vsock_api_command(socket: &mut UnixStream, config: &str) -> Result<(), Error> {
|
fn add_vsock_api_command(socket: &mut UnixStream, config: &str) -> Result<(), Error> {
|
||||||
@ -343,6 +201,7 @@ fn add_vsock_api_command(socket: &mut UnixStream, config: &str) -> Result<(), Er
|
|||||||
"add-vsock",
|
"add-vsock",
|
||||||
Some(&serde_json::to_string(&vsock_config).unwrap()),
|
Some(&serde_json::to_string(&vsock_config).unwrap()),
|
||||||
)
|
)
|
||||||
|
.map_err(Error::ApiClient)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn snapshot_api_command(socket: &mut UnixStream, url: &str) -> Result<(), Error> {
|
fn snapshot_api_command(socket: &mut UnixStream, url: &str) -> Result<(), Error> {
|
||||||
@ -356,6 +215,7 @@ fn snapshot_api_command(socket: &mut UnixStream, url: &str) -> Result<(), Error>
|
|||||||
"snapshot",
|
"snapshot",
|
||||||
Some(&serde_json::to_string(&snapshot_config).unwrap()),
|
Some(&serde_json::to_string(&snapshot_config).unwrap()),
|
||||||
)
|
)
|
||||||
|
.map_err(Error::ApiClient)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn restore_api_command(socket: &mut UnixStream, config: &str) -> Result<(), Error> {
|
fn restore_api_command(socket: &mut UnixStream, config: &str) -> Result<(), Error> {
|
||||||
@ -367,15 +227,20 @@ fn restore_api_command(socket: &mut UnixStream, config: &str) -> Result<(), Erro
|
|||||||
"restore",
|
"restore",
|
||||||
Some(&serde_json::to_string(&restore_config).unwrap()),
|
Some(&serde_json::to_string(&restore_config).unwrap()),
|
||||||
)
|
)
|
||||||
|
.map_err(Error::ApiClient)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_command(matches: &ArgMatches) -> Result<(), Error> {
|
fn do_command(matches: &ArgMatches) -> Result<(), Error> {
|
||||||
let mut socket =
|
let mut socket =
|
||||||
UnixStream::connect(matches.value_of("api-socket").unwrap()).map_err(Error::Socket)?;
|
UnixStream::connect(matches.value_of("api-socket").unwrap()).map_err(Error::Connect)?;
|
||||||
|
|
||||||
match matches.subcommand_name() {
|
match matches.subcommand_name() {
|
||||||
Some("info") => simple_api_command(&mut socket, "GET", "info", None),
|
Some("info") => {
|
||||||
Some("counters") => simple_api_command(&mut socket, "GET", "counters", None),
|
simple_api_command(&mut socket, "GET", "info", None).map_err(Error::ApiClient)
|
||||||
|
}
|
||||||
|
Some("counters") => {
|
||||||
|
simple_api_command(&mut socket, "GET", "counters", None).map_err(Error::ApiClient)
|
||||||
|
}
|
||||||
Some("resize") => resize_api_command(
|
Some("resize") => resize_api_command(
|
||||||
&mut socket,
|
&mut socket,
|
||||||
matches
|
matches
|
||||||
@ -476,7 +341,7 @@ fn do_command(matches: &ArgMatches) -> Result<(), Error> {
|
|||||||
.value_of("restore_config")
|
.value_of("restore_config")
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
),
|
),
|
||||||
Some(c) => simple_api_command(&mut socket, "PUT", c, None),
|
Some(c) => simple_api_command(&mut socket, "PUT", c, None).map_err(Error::ApiClient),
|
||||||
None => unreachable!(),
|
None => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user