changeset 20:da4858f4658d

impl define cmd
author AnaTofuZ <k198584@ie.u-ryukyu.ac.jp>
date Tue, 03 Nov 2020 17:21:27 +0900
parents d37203a877d9
children 9f3d29b8561a
files Cargo.toml src/command.rs src/main.rs src/xml.rs
diffstat 4 files changed, 137 insertions(+), 78 deletions(-) [+]
line wrap: on
line diff
--- a/Cargo.toml	Tue Nov 03 11:10:24 2020 +0900
+++ b/Cargo.toml	Tue Nov 03 17:21:27 2020 +0900
@@ -17,4 +17,4 @@
 [profile.release]
 codegen-units = 1
 lto = true
-opt-level = "z"
+opt-level = 3
--- a/src/command.rs	Tue Nov 03 11:10:24 2020 +0900
+++ b/src/command.rs	Tue Nov 03 17:21:27 2020 +0900
@@ -11,7 +11,10 @@
 }
 
 pub fn define(user_name: &'static str, vm_name: String) {
-    xml::generate();
+    let vm_name = generate_vm_name(user_name, &vm_name);
+    let vm_arg = xml::GenerateVMArg::new(user_name, vm_name, false);
+    vm_arg.generate().ok();
+    exec_cmd_from_name_or_id(user_name, &vm_name, "define")
 }
 
 pub fn start(user_name: &'static str, vm_name: String) {
@@ -88,3 +91,11 @@
     }
     format!("{}-{}", user_name, vm_name)
 }
+
+
+fn generate_vm_name(user_name:&'static str, vm_name: &str) -> String {
+    if vm_name.starts_with(user_name) {
+        return vm_name.to_string();
+    }
+    format!("{}-{}", user_name, vm_name)
+}
\ No newline at end of file
--- a/src/main.rs	Tue Nov 03 11:10:24 2020 +0900
+++ b/src/main.rs	Tue Nov 03 17:21:27 2020 +0900
@@ -120,7 +120,10 @@
             command::start(user_name, arg.name);
         }
 
-        SubCommand::Define(name) => {}
+        SubCommand::Define(arg) => {
+            user::set_root_id();
+            command::define(user_name, arg.name);
+        }
 
         SubCommand::Shutdown(arg) => {
             user::set_root_id();
--- a/src/xml.rs	Tue Nov 03 11:10:24 2020 +0900
+++ b/src/xml.rs	Tue Nov 03 17:21:27 2020 +0900
@@ -1,14 +1,15 @@
 use quick_xml::events::{BytesEnd, BytesStart, BytesText, Event};
 use quick_xml::{Reader, Writer};
 use rand::Rng;
+use std::fs;
 use std::fs::File;
-use std::io::{BufReader, BufWriter, Error, ErrorKind};
+use std::io::{BufReader, BufWriter, Error};
 use std::path::Path;
 use uuid::Uuid;
 
 const CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
                         abcdefghijklmnopqrstuvwxyz\
-                        0123456789)(*&^%$#@!~";
+                        0123456789)(*^%$#@!~";
 
 const PASSWORD_LEN: usize = 30;
 
@@ -23,92 +24,136 @@
 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;
+const TEMPLATE_XML_FILE: &str = "/etc/libvirt/template.xml";
+
+const LIBVIRT_XML_DIR: &str = "/etc/libvirt/qemu";
+const QCOW2_PATH: &str = "/mnt/ie-virsh";
+
+pub struct GenerateVMArg {
+    VMName: String,
+    Qcow2PATH: String,
+    XMLPATH: String,
+    VNCPassword: String,
+    IsDebug: bool,
+    TCPPort: u64,
+}
+
+impl GenerateVMArg {
+    pub fn new(user_name: &'static str, vm_name: String, is_debug: bool) -> GenerateVMArg {
+        let year = user_name.chars().skip(1).take(2).collect::<String>();
+        let affilication = if year.parse::<u8>().is_ok() {
+            // /etc/libvirt/qemu/e19/e195729
+            user_name.chars().take(3).collect::<String>()
+        } else {
+            "teacher".to_string()
+        };
+
+        let xml_dir = format!("{}/{}/{}", LIBVIRT_XML_DIR, affilication, user_name);
+        let xml_path = format!("{}/{}.xml", xml_dir.clone(), vm_name);
+
+        if !Path::new(&xml_dir).exists() {
+            fs::create_dir_all(xml_dir).ok();
+        }
+
+        let qcow2_dir = format!("{}/{}/{}", QCOW2_PATH, affilication, user_name);
+
+        let qcow2_path = format!("{}/{}.qcow2", qcow2_dir.clone(), vm_name);
 
-    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();
-            }
+        if !Path::new(&qcow2_dir).exists() {
+            fs::create_dir_all(qcow2_dir).ok();
+        }
+
+        let pw = generate_pw();
+
+        GenerateVMArg {
+            VMName: vm_name.to_string(),
+            Qcow2PATH: qcow2_path,
+            XMLPATH: xml_path,
+            VNCPassword: pw,
+            IsDebug: is_debug,
+            TCPPort: 90,
+        }
+    }
 
-            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();
+    pub fn generate(self) -> Result<(), Error> {
+        let mut reader = Reader::from_reader(BufReader::new(File::open(TEMPLATE_XML_FILE)?));
 
-                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();
+        println!("generate xml :{}", self.XMLPATH);
+        let mut writer = Writer::new(BufWriter::new(File::create(self.XMLPATH).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();
                 }
 
-                let qemu_command_line_end = BytesEnd::borrowed(QEMU_COMMAND_LINE_TAG);
-                writer
-                    .write_event(Event::End(qemu_command_line_end))
-                    .unwrap();
-            }
+                Ok(Event::Start(ref e)) if (e.name() == ROOT_START_TAG && self.IsDebug) => {
+                    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();
 
-            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();
-            }
+                    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();
+                    }
 
-            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"));
+                    let qemu_command_line_end = BytesEnd::borrowed(QEMU_COMMAND_LINE_TAG);
+                    writer
+                        .write_event(Event::End(qemu_command_line_end))
+                        .unwrap();
                 }
-                writer.write_event(Event::Empty(elem)).ok();
-            }
+
+                Ok(Event::Empty(ref e)) if e.name() == VNC_XML_TAG => {
+                    let mut elem = e.clone();
+                    let pw: &str = &self.VNCPassword;
+                    elem.push_attribute(("passwd", pw));
+                    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::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();
+                        let qcow2_path: &str = &self.Qcow2PATH;
+                        elem.push_attribute(("file", qcow2_path));
+                    }
+                    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(&self.VMName);
+                    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),
             }
-            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();
         }
-        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);
+        Ok(())
     }
 
-    Err(Error::new(ErrorKind::Other, "failed ..."))
+    println!("generate xml : {}", self.XMLPATH);
+    println!("vnc password : {}", self.VNCPassword);
 }
 
 fn generate_pw() -> String {