Mercurial > hg > Members > anatofuz > ie-virsh
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 {