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