230e8558bc3cdd8e78d2af1719ed15fc795bbed1
[nitsi.git] / src / nitsi / machine.py
1 #!/usr/bin/python3
2
3 import xml.etree.ElementTree as ET
4
5 from nitsi.disk import disk
6
7 from nitsi.serial_connection import serial_connection
8
9 import os
10 import libvirt
11
12 import logging
13
14 logger = logging.getLogger("nitsi.machine")
15
16 class machine():
17     def __init__(self, libvirt_con, vm_xml_file, snapshot_xml_file, image, root_uid, username, password):
18         self.log = logger.getChild(os.path.basename(vm_xml_file))
19         self.con = libvirt_con
20         try:
21             with open(vm_xml_file) as fobj:
22                 self.vm_xml = fobj.read()
23         except FileNotFoundError as error:
24             logger.error("No such file: {}".format(vm_xml_file))
25
26         try:
27             self.name = self.get_name()
28         except BaseException as error:
29             logger.error("Could not get name of the machine: {}".format(vm_xml_file))
30             raise error
31
32         self.log = logger.getChild(self.name)
33         self.log.debug("Name of this machine is {}".format(self.name))
34
35         try:
36             with open(snapshot_xml_file) as fobj:
37                 self.snapshot_xml = fobj.read()
38         except FileNotFoundError as error:
39             self.log.error("No such file: {}".format(snapshot_xml_file))
40
41         self.image = image
42
43         if not os.path.isfile(self.image):
44             self.log.error("No such file: {}".format(self.image))
45
46         self.root_uid = root_uid
47         self.disk = disk(image)
48
49         self.username = username
50         self.password = password
51
52     def define(self):
53         self.dom = self.con.defineXML(self.vm_xml)
54         if self.dom == None:
55             self.log.error("Could not define VM")
56             raise BaseException
57
58     def start(self):
59         if self.dom.create() < 0:
60             self.log.error("Could not start VM")
61             raise BaseException
62
63     def shutdown(self):
64         if self.is_running():
65             if self.dom.shutdown() < 0:
66                 self.log.error("Could not shutdown VM")
67                 raise BaseException
68         else:
69             self.log.error("Domain is not running")
70
71     def undefine(self):
72         self.dom.undefine()
73
74     def create_snapshot(self):
75
76         self.snapshot = self.dom.snapshotCreateXML(self.snapshot_xml)
77
78         if not self.snapshot:
79             self.log.error("Could not create snapshot")
80             raise BaseException
81
82     def revert_snapshot(self):
83         self.dom.revertToSnapshot(self.snapshot)
84         self.snapshot.delete()
85
86     def is_running(self):
87
88         state, reason = self.dom.state()
89
90         if state == libvirt.VIR_DOMAIN_RUNNING:
91             return True
92         else:
93             return False
94
95     def get_serial_device(self):
96
97         if not self.is_running():
98             raise BaseException
99
100         xml_root = ET.fromstring(self.dom.XMLDesc(0))
101
102         elem = xml_root.find("./devices/serial/source")
103         return elem.get("path")
104
105     def get_name(self):
106         xml_root = ET.fromstring(self.vm_xml)
107
108         elem = xml_root.find("./name")
109         return elem.text
110
111     def check_is_booted_up(self):
112         serial_con = serial_connection(self.get_serial_device())
113
114         serial_con.write("\n")
115         # This will block till the domain is booted up
116         serial_con.read(1)
117
118         #serial_con.close()
119
120     def login(self, log_file, log_start_time=None):
121         try:
122             self.serial_con = serial_connection(self.get_serial_device(),
123                                 username=self.username,
124                                 log_file=log_file,
125                                 log_start_time=log_start_time,
126                                 name=self.name)
127             self.serial_con.login(self.password)
128         except BaseException as e:
129             self.log.error("Could not connect to the domain via serial console")
130             self.log.exception(e)
131             raise e
132
133     def cmd(self, cmd):
134         return self.serial_con.command(cmd)
135
136     def copy_in(self, fr, to):
137         try:
138             self.disk.mount(self.root_uid, "/")
139             self.disk.copy_in(fr, to)
140         except BaseException as e:
141             self.log.error(e)
142         finally:
143             self.disk.umount("/")
144             self.disk.close()