/
vm.py
192 lines (155 loc) · 5.65 KB
/
vm.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
import os
import uuid
import socket
import subprocess
from libvirtex.connection import LXCDomain, KVMDomain
from libvirtex.devices import FileSystemDevice, ETHNetworkDevice, HDDFileDevice
from vm_utils.cmd_executor import SSHCMDExecutor
from restorablefs import RestorableFS
from utils import shell_exec
class IVM(object):
"""
Interface of class for working with container
"""
def __init__(self, name, login, pwd):
self.name = name
def __enter__(self):
pass
def __exit__(self, type, value, traceback):
#self.stop()
pass
def start(self):
"""starts container"""
return self
def get_ip(self):
return self.ip
def stop(self):
"""stops container"""
pass
def is_ssh_ready(ip, port=22):
"""Checks is port opened on host with given ip """
s = socket.socket()
s.settimeout(0.1)
try:
s.connect((ip, port))
return True
except socket.error, x:
return False
class KVM(IVM):
type_ = 'kvm'
def __init__(self,
name,
img_file,
ip="192.168.122.2",
hwaddr='4A:59:43:49:79:BF',
destroy_on_exit=True,
conn=None):
"""
configures kvm based vm
name - name of your vm
you may change ip or hwaddr if you need
"""
self.img_file = img_file
if not os.path.exists(self.img_file):
raise ValueError("Image file not found: %s" % self.img_file)
self.name = name
self.ip = ip
self.hwaddr = hwaddr
self.vm_file = None
self.conn = conn
def start(self):
"""starts container"""
self.vm_file = "/tmp/{0}.qcow2".format(uuid.uuid1())
shell_exec('qemu-img create -f qcow2 -b "{0}" "{1}"'.
format(self.img_file, self.vm_file))
self.vm = KVMDomain.construct(self.conn,
True,
self.name,
1024 * 1024,
1,
HDDFileDevice(self.vm_file,
type_='qcow2',
dev='hda',
bus='ide'),
ETHNetworkDevice(self.hwaddr,
"vnet7",
ip=self.ip))
return self
def get_ip(self):
return self.ip
def stop(self):
"""stops container"""
self.vm.destroy()
os.unlink(self.vm_file)
class LXC(IVM):
"""Class for working with LXC based virtual machines"""
type_ = 'lxc'
def __init__(self,
name,
fs_file,
ip="192.168.122.2",
hwaddr='4A:59:43:49:79:BF',
destroy_on_exit=True,
conn=None,
lxc_name=None):
"""
configures lxc based vm
name -- name of your vm
you may change ip or hwaddr if you need
fs_file may be changed to your fs(btrfs) file
"""
self.name = name
self.ip = ip
self.hwaddr = hwaddr
self.img_file = fs_file
self.fs = RestorableFS(image_file=fs_file)
self.destroy_on_exit = destroy_on_exit
self.use_libvirt = (conn != None)
self.conn = conn
self.lxc_name = lxc_name if lxc_name is not None else self.name
def start(self, fs_mpoint_folder="/tmp/vms"):
"""
starts lxc based vm
fs_mpoint_folder is a folder where your vms file system
will be mounted in some folder. It should exist
"""
self.started = False
if not os.path.exists(fs_mpoint_folder):
shell_exec('mkdir -p "{0}"'.format(fs_mpoint_folder))
mpoint = os.path.join(fs_mpoint_folder, str(uuid.uuid1()))
shell_exec('mkdir -p "{0}"'.format(mpoint))
self.fs.mount(mpoint)
try:
if self.use_libvirt:
self.vm = LXCDomain.construct(self.conn,
True,
self.name,
1024 * 1024,
2,
FileSystemDevice(mpoint),
ETHNetworkDevice(self.hwaddr,
"vnet7",
ip=self.ip))
else:
shell_exec('lxc-start -d -n "{0}"'.format(self.lxc_name))
except:
self.stop()
raise
logger.info("Domain started ok with ip {0!r} wait ssh ready".format(self.ip))
for i in range(100):
if is_ssh_ready(self.ip):
self.started = True
return self
logger.critical("ssh failed to start on ip {0!r}".format(self.ip))
self.stop()
raise Exception("VM refuses to start")
def stop(self):
"""Stops vm. Destroys changes on it """
if self.destroy_on_exit:
if self.started:
if self.use_libvirt:
self.vm.destroy()
else:
shell_exec('lxc-stop -n "{0}"'.format(self.lxc_name))
self.fs.umount()
shell_exec('rm -rf "{0}"'.format(self.fs.mpoint))