changeset 19:d37203a877d9

add xml parse/writer
author AnaTofuZ <k198584@ie.u-ryukyu.ac.jp>
date Tue, 03 Nov 2020 11:10:24 +0900
parents 9b24d6767a2f
children da4858f4658d
files Cargo.lock Cargo.toml src/command.rs src/lib.rs src/main.rs src/xml.rs
diffstat 6 files changed, 255 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/Cargo.lock	Mon Nov 02 18:59:52 2020 +0900
+++ b/Cargo.lock	Tue Nov 03 11:10:24 2020 +0900
@@ -68,6 +68,17 @@
 ]
 
 [[package]]
+name = "getrandom"
+version = "0.1.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
+
+[[package]]
 name = "hashbrown"
 version = "0.9.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -98,6 +109,9 @@
  "clap",
  "libc",
  "nix",
+ "quick-xml",
+ "rand",
+ "uuid",
 ]
 
 [[package]]
@@ -123,6 +137,12 @@
 checksum = "2448f6066e80e3bfc792e9c98bf705b4b0fc6e8ef5b43e5889aff0eaa9c58743"
 
 [[package]]
+name = "memchr"
+version = "2.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
+
+[[package]]
 name = "nix"
 version = "0.19.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -141,6 +161,12 @@
 checksum = "2ac6fe3538f701e339953a3ebbe4f39941aababa8a3f6964635b24ab526daeac"
 
 [[package]]
+name = "ppv-lite86"
+version = "0.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
+
+[[package]]
 name = "proc-macro-error"
 version = "1.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -174,6 +200,15 @@
 ]
 
 [[package]]
+name = "quick-xml"
+version = "0.20.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26aab6b48e2590e4a64d1ed808749ba06257882b461d01ca71baeb747074a6dd"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
 name = "quote"
 version = "1.0.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -183,6 +218,47 @@
 ]
 
 [[package]]
+name = "rand"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
+dependencies = [
+ "getrandom",
+ "libc",
+ "rand_chacha",
+ "rand_core",
+ "rand_hc",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
+dependencies = [
+ "ppv-lite86",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
+dependencies = [
+ "getrandom",
+]
+
+[[package]]
+name = "rand_hc"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
+dependencies = [
+ "rand_core",
+]
+
+[[package]]
 name = "strsim"
 version = "0.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -236,6 +312,15 @@
 checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
 
 [[package]]
+name = "uuid"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9fde2f6a4bea1d6e007c4ad38c6839fa71cbb63b6dbf5b595aa38dc9b1093c11"
+dependencies = [
+ "rand",
+]
+
+[[package]]
 name = "vec_map"
 version = "0.8.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -248,6 +333,12 @@
 checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
 
 [[package]]
+name = "wasi"
+version = "0.9.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
+
+[[package]]
 name = "winapi"
 version = "0.3.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
--- a/Cargo.toml	Mon Nov 02 18:59:52 2020 +0900
+++ b/Cargo.toml	Tue Nov 03 11:10:24 2020 +0900
@@ -10,6 +10,9 @@
 nix = "0.19.0"
 libc = "0.2.77"
 clap = "3.0.0-beta.2"
+quick-xml = "0.20.0"
+uuid = { version = "0.8", features = ["v4"] }
+rand = "0.7"
 
 [profile.release]
 codegen-units = 1
--- a/src/command.rs	Mon Nov 02 18:59:52 2020 +0900
+++ b/src/command.rs	Tue Nov 03 11:10:24 2020 +0900
@@ -1,4 +1,5 @@
 use super::virsh;
+use super::xml;
 
 pub fn list(user_name: &'static str) {
     let (ldump_msg, vm_list_strs) = virsh::get_vm_list(user_name);
@@ -9,6 +10,10 @@
     }
 }
 
+pub fn define(user_name: &'static str, vm_name: String) {
+    xml::generate();
+}
+
 pub fn start(user_name: &'static str, vm_name: String) {
     virsh::command_require_vm_name(get_vm_name(user_name, &vm_name), "start");
 }
@@ -41,6 +46,13 @@
     exec_cmd_from_name_or_id(user_name, &vm_name, "undefine")
 }
 
+pub fn domiflist(user_name: &'static str, vm_name: String) {
+    exec_cmd_from_name_or_id(user_name, &vm_name, "domiflist")
+}
+
+pub fn dominfo(user_name: &'static str, vm_name: String) {
+    exec_cmd_from_name_or_id(user_name, &vm_name, "dominfo")
+}
 
 fn exec_cmd_from_name_or_id(user_name: &'static str, name_or_id: &str, command: &str) {
     if name_or_id.parse::<u8>().is_ok() {
--- a/src/lib.rs	Mon Nov 02 18:59:52 2020 +0900
+++ b/src/lib.rs	Tue Nov 03 11:10:24 2020 +0900
@@ -1,3 +1,4 @@
 pub mod command;
 pub mod user;
 pub mod virsh;
+pub mod xml;
--- a/src/main.rs	Mon Nov 02 18:59:52 2020 +0900
+++ b/src/main.rs	Tue Nov 03 11:10:24 2020 +0900
@@ -21,6 +21,8 @@
     VNCDisplay(VNCDisplay),
     DumpXML(DumpXML),
     DefineGDB(DefineGDB),
+    DomIfList(DomIfList),
+    DomInfo(DomInfo),
 }
 
 /// define the domain in which the gdb port is opened from the template XML file
@@ -87,6 +89,18 @@
     name: String,
 }
 
+/// list all domain virtual interfaces
+#[derive(Clap)]
+struct DomIfList {
+    name: String,
+}
+
+/// domain information
+#[derive(Clap)]
+struct DomInfo {
+    name: String,
+}
+
 fn main() {
     let opts: Opts = Opts::parse();
 
@@ -143,9 +157,16 @@
             command::undefine(user_name, arg.name);
         }
 
+        SubCommand::DomIfList(arg) => {
+            user::set_root_id();
+            command::domiflist(user_name, arg.name);
+        }
+
+        SubCommand::DomInfo(arg) => {
+            user::set_root_id();
+            command::dominfo(user_name, arg.name);
+        }
+
         _ => {}
     }
-
-    //set_root_id();
-    //list_command(user_name);
-}
\ No newline at end of file
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/xml.rs	Tue Nov 03 11:10:24 2020 +0900
@@ -0,0 +1,123 @@
+use quick_xml::events::{BytesEnd, BytesStart, BytesText, Event};
+use quick_xml::{Reader, Writer};
+use rand::Rng;
+use std::fs::File;
+use std::io::{BufReader, BufWriter, Error, ErrorKind};
+use std::path::Path;
+use uuid::Uuid;
+
+const CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
+                        abcdefghijklmnopqrstuvwxyz\
+                        0123456789)(*&^%$#@!~";
+
+const PASSWORD_LEN: usize = 30;
+
+const DOMAIN_XMLNS_QEMU: (&str, &str) =
+    ("xmlns:qemu", "http://libvirt.org/schemas/domain/qemu/1.0");
+
+const IE_VIRSH_TEMPLATE_VM_NAME: &[u8; 17] = b"ie-virsh-template";
+const VNC_XML_TAG: &[u8; 8] = b"graphics";
+
+const ROOT_START_TAG: &[u8; 6] = b"domain";
+
+const QEMU_COMMAND_LINE_TAG: &[u8; 16] = b"qemu:commandline";
+const QEMU_ARG_TAG: &[u8; 8] = b"qemu:arg";
+
+pub fn generate() -> Result<(), Error> {
+    let is_debug = true;
+
+    let file = "./template.xml";
+    let mut reader = Reader::from_reader(BufReader::new(get_xml_from_file(file)?));
+    let mut writer = Writer::new(BufWriter::new(File::create("dump.xml").unwrap()));
+    let mut buf = Vec::new();
+    loop {
+        match reader.read_event(&mut buf) {
+            Ok(Event::Start(ref e)) if e.name() == b"uuid" => {
+                writer
+                    .write_event(Event::Start(e.clone()))
+                    .expect("faild write event");
+                reader
+                    .read_event(&mut Vec::new())
+                    .expect("faild read event");
+                let vm_uuid = Uuid::new_v4().to_string();
+                let elem = BytesText::from_plain_str(&vm_uuid);
+                writer.write_event(Event::Text(elem)).unwrap();
+            }
+
+            Ok(Event::Start(ref e)) if (e.name() == ROOT_START_TAG && is_debug) => {
+                let mut elem = e.clone();
+                elem.push_attribute(DOMAIN_XMLNS_QEMU);
+                writer.write_event(Event::Start(elem)).unwrap();
+
+                let qemu_command_line_start = BytesStart::borrowed_name(QEMU_COMMAND_LINE_TAG);
+                writer
+                    .write_event(Event::Start(qemu_command_line_start))
+                    .unwrap();
+
+                for value in ["-S", "-gdb", "tcp"].iter() {
+                    let mut qemu_elem = BytesStart::borrowed_name(QEMU_ARG_TAG);
+                    let v: &str = &value;
+                    qemu_elem.push_attribute(("value", v));
+                    writer.write_event(Event::Empty(qemu_elem)).unwrap();
+                }
+
+                let qemu_command_line_end = BytesEnd::borrowed(QEMU_COMMAND_LINE_TAG);
+                writer
+                    .write_event(Event::End(qemu_command_line_end))
+                    .unwrap();
+            }
+
+            Ok(Event::Empty(ref e)) if e.name() == VNC_XML_TAG => {
+                let mut elem = e.clone();
+                let pw: &str = &generate_pw();
+                elem.push_attribute(("passwd", pw));
+                writer.write_event(Event::Empty(elem)).ok();
+            }
+
+            Ok(Event::Empty(ref e)) if (e.name() == b"source") => {
+                let mut elem = e.clone();
+                let is_qcow_file = elem
+                    .attributes()
+                    .find(|attr| attr.as_ref().unwrap().key == b"file");
+                if is_qcow_file.is_some() {
+                    elem.clear_attributes();
+                    elem.push_attribute(("file", "qcow"));
+                }
+                writer.write_event(Event::Empty(elem)).ok();
+            }
+
+            Ok(Event::Text(ref e)) if e.escaped() == IE_VIRSH_TEMPLATE_VM_NAME => {
+                let elem = BytesText::from_plain_str("anatofuz-vm");
+                writer.write_event(Event::Text(elem)).unwrap();
+            }
+            Ok(Event::Eof) => break,
+            // you can use either `e` or `&e` if you don't want to move the event
+            Ok(e) => assert!(writer.write_event(&e).is_ok()),
+            Err(e) => panic!("Error at position {}: {:?}", reader.buffer_position(), e),
+        }
+        buf.clear();
+    }
+    Ok(())
+}
+
+fn get_xml_from_file(source: &str) -> Result<File, Error> {
+    let local_path = Path::new(source);
+
+    if local_path.is_file() {
+        let file = File::open(local_path)?;
+        return Ok(file);
+    }
+
+    Err(Error::new(ErrorKind::Other, "failed ..."))
+}
+
+fn generate_pw() -> String {
+    let mut rng = rand::thread_rng();
+
+    (0..PASSWORD_LEN)
+        .map(|_| {
+            let idx = rng.gen_range(0, CHARSET.len());
+            CHARSET[idx] as char
+        })
+        .collect()
+}