changeset 39:f667f3a4bbee

backing file cmd
author AnaTofuZ <anatofuz@gmail.com>
date Sun, 22 Nov 2020 15:47:37 +0900
parents 6f1b90844b7f
children d3055f6c6fb7
files src/command.rs src/main.rs src/virsh.rs src/xml.rs
diffstat 4 files changed, 81 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/src/command.rs	Sun Nov 22 11:21:18 2020 +0900
+++ b/src/command.rs	Sun Nov 22 15:47:37 2020 +0900
@@ -25,31 +25,47 @@
 
 pub fn define(user: &user::User, vm_name: &str) {
     let vm_name = generate_vm_name(&user.name, &vm_name);
-    let vm_xml = xml::Builder::new(&user.name, &vm_name).finalize();
-    if let Ok(xml_path) = vm_xml.generate() {
-        virsh::command_require_vm_name(xml_path, "define")
+    let builder = xml::Builder::new(&user.name, &vm_name).finalize();
+    if let Ok(xml_path) = builder.generate() {
+        virsh::command_require_vm_name(&xml_path, "define")
+    }
+}
+
+pub fn define_from_template(user: &user::User, vm_name: &str, template: &str) {
+    let vm_name = generate_vm_name(&user.name, &vm_name);
+    let template_path = match virsh::get_template_path(template) {
+        Some(path) => path,
+        None => {
+            println!("not found {}", template);
+            return;
+        }
+    };
+    let builder = xml::Builder::new(&user.name, &vm_name)
+        .backing(&template_path)
+        .finalize();
+    if let Ok(xml_path) = builder.generate() {
+        virsh::command_require_vm_name(&xml_path, "define")
     }
 }
 
 pub fn start(user_name: &str, vm_name: &str) {
-    virsh::command_require_vm_name(get_vm_name(user_name, vm_name), "start");
+    virsh::command_require_vm_name(&get_vm_name(user_name, vm_name), "start");
 }
 
 pub fn common(user_name: &str, vm_name: &str, command: &str) {
     exec_cmd_from_name_or_id(user_name, vm_name, command)
 }
 
-
 pub fn dumpvncpasswd(_user_name: &str, _vm_name: &str) {}
 
 fn exec_cmd_from_name_or_id(user_name: &str, name_or_id: &str, command: &str) {
     if name_or_id.parse::<u8>().is_ok() {
         let vm_name_or_none = get_vm_name_from_id(user_name, &name_or_id);
         if let Some(vm_name) = vm_name_or_none {
-            return virsh::command_require_vm_name(vm_name, command);
+            return virsh::command_require_vm_name(&vm_name, command);
         }
     }
-    virsh::command_require_vm_name(get_vm_name(user_name, name_or_id), command);
+    virsh::command_require_vm_name(&get_vm_name(user_name, name_or_id), command);
 }
 
 fn get_vm_name_from_id(user_name: &str, arg_id: &str) -> Option<String> {
--- a/src/main.rs	Sun Nov 22 11:21:18 2020 +0900
+++ b/src/main.rs	Sun Nov 22 15:47:37 2020 +0900
@@ -40,6 +40,9 @@
 #[derive(Clap)]
 struct Define {
     name: String,
+    /// A level of verbosity, and can be used multiple times
+    #[clap(short, long, parse(from_str))]
+    template: Option<String>,
 }
 
 /// domain information in XML
@@ -132,6 +135,11 @@
                 gid,
                 name: user_name,
             };
+
+            if let Some(template) = arg.template {
+                command::define_from_template(&user, &arg.name, &template);
+                return;
+            }
             command::define(&user, &arg.name);
         }
 
--- a/src/virsh.rs	Sun Nov 22 11:21:18 2020 +0900
+++ b/src/virsh.rs	Sun Nov 22 15:47:37 2020 +0900
@@ -2,10 +2,12 @@
 use std::process::Command;
 
 use std::fs;
+use std::path::Path;
 
 const TEMPLATE_DIR: &str = "/ie-ryukyu/kvm/images/templates/";
 const TEMPLATE_SUFFIX: &str = "template-";
 const TEMPLATE_FILE_EXTENSION: &str = ".qcow2";
+const QCOW2: &str = "qcow2";
 
 pub struct ListDumpMsg {
     pub info_msg: String,
@@ -55,7 +57,7 @@
     )
 }
 
-pub fn command_require_vm_name(vm_name: String, operation: &str) {
+pub fn command_require_vm_name(vm_name: &str, operation: &str) {
     let output = Command::new("virsh")
         .arg(operation)
         .arg(vm_name)
@@ -65,3 +67,35 @@
     io::stdout().write_all(&output.stdout).unwrap();
     io::stderr().write_all(&output.stderr).unwrap();
 }
+
+pub fn generate_qemu_from_template(vm_name: &str, template_path: &str) {
+    let vm_path = format!(
+        "{}{}{}{}",
+        TEMPLATE_DIR, TEMPLATE_SUFFIX, &vm_name, TEMPLATE_FILE_EXTENSION
+    );
+    //$qemu-img create -F qcow2 -b ibm-master.qcow2 -f qcow2 ibm-02.qcow2
+    let output = Command::new("qemu-img")
+        .arg("create")
+        .arg("-F")
+        .arg(QCOW2)
+        .arg("-b")
+        .arg(template_path)
+        .arg("-f")
+        .arg(QCOW2)
+        .arg(vm_path)
+        .output()
+        .unwrap_or_else(|_| panic!("failed to generate {}", &vm_name));
+    io::stdout().write_all(&output.stdout).unwrap();
+    io::stderr().write_all(&output.stderr).unwrap();
+}
+
+pub fn get_template_path(template_name: &str) -> Option<String> {
+    let template_path = format!(
+        "{}{}{}{}",
+        TEMPLATE_DIR, TEMPLATE_SUFFIX, &template_name, TEMPLATE_FILE_EXTENSION
+    );
+    if Path::new(&template_path).exists() {
+        return Some(template_path);
+    }
+    None
+}
--- a/src/xml.rs	Sun Nov 22 11:21:18 2020 +0900
+++ b/src/xml.rs	Sun Nov 22 15:47:37 2020 +0900
@@ -54,7 +54,8 @@
     user_name: String,
     vm_name: String,
     debug_tcp_port: Option<u64>,
-    backing_file: Option<String>,
+    backing_file: String,
+    is_backing: bool,
 }
 
 pub struct GenerateVM {
@@ -63,7 +64,8 @@
     xml_path: String,
     vnc_password: String,
     debug_tcp_port: Option<u64>,
-    backing_file: Option<String>,
+    backing_file: String,
+    is_backing: bool,
 }
 
 impl Builder {
@@ -72,7 +74,8 @@
             user_name: user_name.to_string(),
             vm_name: vm_name.to_string(),
             debug_tcp_port: None,
-            backing_file: None,
+            backing_file: "".to_string(),
+            is_backing: false,
         }
     }
 
@@ -81,12 +84,12 @@
         self
     }
 
-    pub fn backing(&mut self, backing_file: Option<String>) -> &mut Builder {
-        self.backing_file = backing_file;
+    pub fn backing(&mut self, backing_file: &str) -> &mut Builder {
+        self.backing_file = backing_file.to_string();
         self
     }
 
-    pub fn finalize(self) -> GenerateVM {
+    pub fn finalize(&self) -> GenerateVM {
         let year = self.user_name.chars().skip(1).take(2).collect::<String>();
         let affilication = if year.parse::<u8>().is_ok() {
             // /etc/libvirt/qemu/e19/e195729
@@ -111,13 +114,16 @@
         }
 
         let pw = generate_pw();
+
+
         GenerateVM {
             vm_name: self.vm_name.clone(),
             qcow2_path,
             xml_path,
             vnc_password: pw,
             debug_tcp_port: self.debug_tcp_port,
-            backing_file: self.backing_file,
+            backing_file: self.backing_file.clone(),
+            is_backing: self.is_backing,
         }
     }
 }
@@ -183,7 +189,7 @@
                 }
 
                 // use template qcow2
-                Ok(Event::End(ref e)) if ((e.name() == b"disk") && self.backing_file.is_some()) => {
+                Ok(Event::End(ref e)) if ((e.name() == b"disk") && self.is_backing) => {
                     let mut backing_store_start = BytesStart::borrowed_name(b"backingStore");
                     backing_store_start.push_attribute(("type", "file"));
                     backing_store_start.push_attribute(("index", "3"));
@@ -199,7 +205,7 @@
                     writer.write(b"\n").unwrap();
 
                     let mut backing_sorce = BytesStart::borrowed_name(b"sorce");
-                    let backing_file: &str = self.backing_file.as_ref().unwrap();
+                    let backing_file: &str = &self.backing_file;
                     backing_sorce.push_attribute(("file", backing_file));
                     writer.write_event(Event::Empty(backing_sorce)).unwrap();
                     writer.write(b"\n").unwrap();